summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/files/controller/apicontroller.php2
-rw-r--r--apps/files/js/fileactions.js2
-rw-r--r--apps/files/js/filelist.js26
-rw-r--r--apps/files/js/files.js4
-rw-r--r--apps/files/js/jquery-visibility.js101
-rw-r--r--apps/files/tests/js/filelistSpec.js2
-rw-r--r--apps/files_external/3rdparty/.gitignore3
-rw-r--r--apps/files_external/3rdparty/composer.json2
-rw-r--r--apps/files_external/3rdparty/composer.lock14
-rw-r--r--apps/files_external/3rdparty/composer/installed.json12
-rw-r--r--apps/files_external/3rdparty/icewind/smb/.travis.yml50
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/AbstractShare.php26
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/Connection.php25
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/ErrorCodes.php1
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/Exception/InvalidPathException.php10
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/Exception/NoLoginServerException.php (renamed from apps/files_external/3rdparty/icewind/smb/tests/bootstrap.php)5
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/NativeServer.php7
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/NativeShare.php15
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/Server.php33
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/Share.php44
-rw-r--r--apps/files_external/3rdparty/icewind/smb/tests/AbstractShare.php539
-rw-r--r--apps/files_external/3rdparty/icewind/smb/tests/NativeShare.php27
-rw-r--r--apps/files_external/3rdparty/icewind/smb/tests/NativeStream.php143
-rw-r--r--apps/files_external/3rdparty/icewind/smb/tests/Parser.php103
-rw-r--r--apps/files_external/3rdparty/icewind/smb/tests/Server.php57
-rw-r--r--apps/files_external/3rdparty/icewind/smb/tests/Share.php24
-rw-r--r--apps/files_external/3rdparty/icewind/smb/tests/config.json7
-rw-r--r--apps/files_external/3rdparty/icewind/smb/tests/phpunit.xml6
-rw-r--r--apps/files_external/appinfo/app.php15
-rw-r--r--apps/files_external/appinfo/application.php32
-rw-r--r--apps/files_external/appinfo/routes.php3
-rw-r--r--apps/files_external/controller/globalstoragescontroller.php55
-rw-r--r--apps/files_external/controller/storagescontroller.php109
-rw-r--r--apps/files_external/controller/userstoragescontroller.php56
-rw-r--r--apps/files_external/js/settings.js126
-rw-r--r--apps/files_external/lib/auth/authmechanism.php116
-rw-r--r--apps/files_external/lib/auth/builtin.php41
-rw-r--r--apps/files_external/lib/auth/nullmechanism.php41
-rw-r--r--apps/files_external/lib/backend/backend.php164
-rw-r--r--apps/files_external/lib/backend/legacybackend.php85
-rw-r--r--apps/files_external/lib/config.php673
-rw-r--r--apps/files_external/lib/config/configadapter.php124
-rw-r--r--apps/files_external/lib/definitionparameter.php179
-rw-r--r--apps/files_external/lib/dependencytrait.php86
-rw-r--r--apps/files_external/lib/failedstorage.php200
-rw-r--r--apps/files_external/lib/frontenddefinitiontrait.php147
-rw-r--r--apps/files_external/lib/identifiertrait.php68
-rw-r--r--apps/files_external/lib/insufficientdataformeaningfulanswerexception.php30
-rw-r--r--apps/files_external/lib/missingdependency.php64
-rw-r--r--apps/files_external/lib/personalmount.php45
-rw-r--r--apps/files_external/lib/prioritytrait.php60
-rw-r--r--apps/files_external/lib/storageconfig.php68
-rw-r--r--apps/files_external/lib/storagemodifiertrait.php67
-rw-r--r--apps/files_external/lib/visibilitytrait.php136
-rw-r--r--apps/files_external/personal.php38
-rw-r--r--apps/files_external/service/backendservice.php275
-rw-r--r--apps/files_external/service/globalstoragesservice.php2
-rw-r--r--apps/files_external/service/storagesservice.php140
-rw-r--r--apps/files_external/service/userglobalstoragesservice.php107
-rw-r--r--apps/files_external/service/userstoragesservice.php33
-rw-r--r--apps/files_external/service/usertrait.php74
-rw-r--r--apps/files_external/settings.php53
-rw-r--r--apps/files_external/templates/settings.php237
-rw-r--r--apps/files_external/tests/auth/authmechanismtest.php80
-rw-r--r--apps/files_external/tests/backend/backendtest.php89
-rw-r--r--apps/files_external/tests/backend/legacybackendtest.php81
-rw-r--r--apps/files_external/tests/controller/globalstoragescontrollertest.php4
-rw-r--r--apps/files_external/tests/controller/storagescontrollertest.php162
-rw-r--r--apps/files_external/tests/controller/userstoragescontrollertest.php55
-rw-r--r--apps/files_external/tests/definitionparameterttest.php70
-rw-r--r--apps/files_external/tests/dependencytraittest.php45
-rw-r--r--apps/files_external/tests/dynamicmountconfig.php104
-rw-r--r--apps/files_external/tests/frontenddefinitiontraittest.php83
-rw-r--r--apps/files_external/tests/js/settingsSpec.js22
-rw-r--r--apps/files_external/tests/mountconfig.php1157
-rw-r--r--apps/files_external/tests/service/backendservicetest.php152
-rw-r--r--apps/files_external/tests/service/globalstoragesservicetest.php144
-rw-r--r--apps/files_external/tests/service/storagesservicetest.php171
-rw-r--r--apps/files_external/tests/service/userglobalstoragesservicetest.php215
-rw-r--r--apps/files_external/tests/service/userstoragesservicetest.php20
-rw-r--r--apps/files_external/tests/storageconfigtest.php18
-rw-r--r--apps/files_sharing/api/server2server.php8
-rw-r--r--apps/files_sharing/lib/share/folder.php2
-rw-r--r--apps/files_sharing/templates/public.php1
-rw-r--r--apps/user_ldap/appinfo/app.php7
-rw-r--r--apps/user_ldap/lib/helper.php31
-rw-r--r--apps/user_ldap/user_ldap.php60
-rw-r--r--apps/user_ldap/user_proxy.php13
88 files changed, 4582 insertions, 3251 deletions
diff --git a/apps/files/controller/apicontroller.php b/apps/files/controller/apicontroller.php
index 0cc222d7ce9..494d97db7a6 100644
--- a/apps/files/controller/apicontroller.php
+++ b/apps/files/controller/apicontroller.php
@@ -78,7 +78,7 @@ class ApiController extends Controller {
return new DataResponse(['message' => 'Requested size must be numeric and a positive value.'], Http::STATUS_BAD_REQUEST);
}
- $preview = $this->previewManager->createPreview('files/'.urldecode($file), $x, $y, true);
+ $preview = $this->previewManager->createPreview('files/'.$file, $x, $y, true);
if ($preview->valid()) {
return new DataDisplayResponse($preview->data(), Http::STATUS_OK, ['Content-Type' => 'image/png']);
} else {
diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js
index 1d0493f2140..f3f137a0537 100644
--- a/apps/files/js/fileactions.js
+++ b/apps/files/js/fileactions.js
@@ -616,7 +616,7 @@
name: 'Delete',
mime: 'all',
// permission is READ because we show a hint instead if there is no permission
- permissions: OC.PERMISSION_READ,
+ permissions: OC.PERMISSION_DELETE,
icon: function() {
return OC.imagePath('core', 'actions/delete');
},
diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index e00cbfa66ab..68c1f9d919f 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -1933,6 +1933,8 @@
updateSelectionSummary: function() {
var summary = this._selectionSummary.summary;
var canDelete;
+ var selection;
+
if (summary.totalFiles === 0 && summary.totalDirs === 0) {
this.$el.find('#headerName a.name>span:first').text(t('files','Name'));
this.$el.find('#headerSize a>span:first').text(t('files','Size'));
@@ -1944,16 +1946,22 @@
canDelete = (this.getDirectoryPermissions() & OC.PERMISSION_DELETE) && this.isSelectedDeletable();
this.$el.find('.selectedActions').removeClass('hidden');
this.$el.find('#headerSize a>span:first').text(OC.Util.humanFileSize(summary.totalSize));
- var selection = '';
- if (summary.totalDirs > 0) {
- selection += n('files', '%n folder', '%n folders', summary.totalDirs);
- if (summary.totalFiles > 0) {
- selection += ' & ';
- }
- }
- if (summary.totalFiles > 0) {
- selection += n('files', '%n file', '%n files', summary.totalFiles);
+
+ var directoryInfo = n('files', '%n folder', '%n folders', summary.totalDirs);
+ var fileInfo = n('files', '%n file', '%n files', summary.totalFiles);
+
+ if (summary.totalDirs > 0 && summary.totalFiles > 0) {
+ var selectionVars = {
+ dirs: directoryInfo,
+ files: fileInfo
+ };
+ selection = t('files', '{dirs} and {files}', selectionVars);
+ } else if (summary.totalDirs > 0) {
+ selection = directoryInfo;
+ } else {
+ selection = fileInfo;
}
+
this.$el.find('#headerName a.name>span:first').text(selection);
this.$el.find('#modified a>span:first').text('');
this.$el.find('table').addClass('multiselect');
diff --git a/apps/files/js/files.js b/apps/files/js/files.js
index f70055d0f52..245648a79e2 100644
--- a/apps/files/js/files.js
+++ b/apps/files/js/files.js
@@ -246,12 +246,12 @@
// Use jquery-visibility to de-/re-activate file stats sync
if ($.support.pageVisibility) {
$(document).on({
- 'show.visibility': function() {
+ 'show': function() {
if (!updateStorageStatisticsIntervalId) {
updateStorageStatisticsIntervalId = setInterval(func, updateStorageStatisticsInterval);
}
},
- 'hide.visibility': function() {
+ 'hide': function() {
clearInterval(updateStorageStatisticsIntervalId);
updateStorageStatisticsIntervalId = 0;
}
diff --git a/apps/files/js/jquery-visibility.js b/apps/files/js/jquery-visibility.js
index 18f57d1f2bd..4d65e7771f9 100644
--- a/apps/files/js/jquery-visibility.js
+++ b/apps/files/js/jquery-visibility.js
@@ -1,31 +1,88 @@
-/*! http://mths.be/visibility v1.0.5 by @mathias */
-(function (window, document, $, undefined) {
+/*!
+ * jquery-visibility v1.0.11
+ * Page visibility shim for jQuery.
+ *
+ * Project Website: http://mths.be/visibility
+ *
+ * @version 1.0.11
+ * @license MIT.
+ * @author Mathias Bynens - @mathias
+ * @author Jan Paepke - @janpaepke
+ */
+;(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['jquery'], function ($) {
+ return factory(root, $);
+ });
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS
+ module.exports = factory(root, require('jquery'));
+ } else {
+ // Browser globals
+ factory(root, jQuery);
+ }
+}(this, function(window, $, undefined) {
+ "use strict";
- var prefix,
- property,
- // In Opera, `'onfocusin' in document == true`, hence the extra `hasFocus` check to detect IE-like behavior
- eventName = 'onfocusin' in document && 'hasFocus' in document ? 'focusin focusout' : 'focus blur',
- prefixes = ['', 'moz', 'ms', 'o', 'webkit'],
- $support = $.support,
- $event = $.event;
+ var
+ document = window.document,
+ property, // property name of document, that stores page visibility
+ vendorPrefixes = ['webkit', 'o', 'ms', 'moz', ''],
+ $support = $.support || {},
+ // In Opera, `'onfocusin' in document == true`, hence the extra `hasFocus` check to detect IE-like behavior
+ eventName = 'onfocusin' in document && 'hasFocus' in document ?
+ 'focusin focusout' :
+ 'focus blur';
- while ((property = prefix = prefixes.pop()) != undefined) {
- property = (prefix ? prefix + 'H' : 'h') + 'idden';
- if ($support.pageVisibility = typeof document[property] == 'boolean') {
+ var prefix;
+ while ((prefix = vendorPrefixes.pop()) !== undefined) {
+ property = (prefix ? prefix + 'H': 'h') + 'idden';
+ $support.pageVisibility = document[property] !== undefined;
+ if ($support.pageVisibility) {
eventName = prefix + 'visibilitychange';
break;
}
}
- $(/blur$/.test(eventName) ? window : document).on(eventName, function (event) {
- var type = event.type,
- originalEvent = event.originalEvent;
- // If it’s a `{focusin,focusout}` event (IE), `fromElement` and `toElement` should both be `null` or `undefined`;
- // else, the page visibility hasn’t changed, but the user just clicked somewhere in the doc.
- // In IE9, we need to check the `relatedTarget` property instead.
- if (!/^focus./.test(type) || originalEvent == undefined || (originalEvent.toElement == undefined && originalEvent.fromElement == undefined && originalEvent.relatedTarget == undefined)) {
- $event.trigger((property && document[property] || /^(?:blur|focusout)$/.test(type) ? 'hide' : 'show') + '.visibility');
+ // normalize to and update document hidden property
+ function updateState() {
+ if (property !== 'hidden') {
+ document.hidden = $support.pageVisibility ? document[property] : undefined;
}
- });
+ }
+ updateState();
-}(this, document, jQuery));
+ $(/blur$/.test(eventName) ? window : document).on(eventName, function(event) {
+ var type = event.type;
+ var originalEvent = event.originalEvent;
+
+ // Avoid errors from triggered native events for which `originalEvent` is
+ // not available.
+ if (!originalEvent) {
+ return;
+ }
+
+ var toElement = originalEvent.toElement;
+
+ // If it’s a `{focusin,focusout}` event (IE), `fromElement` and `toElement`
+ // should both be `null` or `undefined`; else, the page visibility hasn’t
+ // changed, but the user just clicked somewhere in the doc. In IE9, we need
+ // to check the `relatedTarget` property instead.
+ if (
+ !/^focus./.test(type) || (
+ toElement === undefined &&
+ originalEvent.fromElement === undefined &&
+ originalEvent.relatedTarget === undefined
+ )
+ ) {
+ $(document).triggerHandler(
+ property && document[property] || /^(?:blur|focusout)$/.test(type) ?
+ 'hide' :
+ 'show'
+ );
+ }
+ // and update the current state
+ updateState();
+ });
+}));
diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js
index 38073389382..7ed60084fa9 100644
--- a/apps/files/tests/js/filelistSpec.js
+++ b/apps/files/tests/js/filelistSpec.js
@@ -1606,7 +1606,7 @@ describe('OCA.Files.FileList tests', function() {
fileList.findFileEl('One.txt').find('input:checkbox').click();
fileList.findFileEl('Three.pdf').find('input:checkbox').click();
fileList.findFileEl('somedir').find('input:checkbox').click();
- expect($summary.text()).toEqual('1 folder & 2 files');
+ expect($summary.text()).toEqual('1 folder and 2 files');
});
it('Unselecting files hides selection summary', function() {
var $summary = $('#headerName a.name>span:first');
diff --git a/apps/files_external/3rdparty/.gitignore b/apps/files_external/3rdparty/.gitignore
index a9a7266a624..c8d4e6eed0b 100644
--- a/apps/files_external/3rdparty/.gitignore
+++ b/apps/files_external/3rdparty/.gitignore
@@ -1 +1,4 @@
example.php
+icewind/smb/tests
+icewind/smb/install_libsmbclient.sh
+icewind/smb/.travis.yml
diff --git a/apps/files_external/3rdparty/composer.json b/apps/files_external/3rdparty/composer.json
index 9680d92e548..ad007df23de 100644
--- a/apps/files_external/3rdparty/composer.json
+++ b/apps/files_external/3rdparty/composer.json
@@ -6,7 +6,7 @@
"vendor-dir": "."
},
"require": {
- "icewind/smb": "1.0.1",
+ "icewind/smb": "1.0.4",
"icewind/streams": "0.2"
}
}
diff --git a/apps/files_external/3rdparty/composer.lock b/apps/files_external/3rdparty/composer.lock
index 84fbb046d5a..033a5a17a13 100644
--- a/apps/files_external/3rdparty/composer.lock
+++ b/apps/files_external/3rdparty/composer.lock
@@ -1,23 +1,23 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
- "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "hash": "7b46d64e33feb600c5f0ec830b211e6f",
+ "hash": "5c612406bc1235075305b09a5d6996a9",
"packages": [
{
"name": "icewind/smb",
- "version": "v1.0.1",
+ "version": "v1.0.4",
"source": {
"type": "git",
"url": "https://github.com/icewind1991/SMB.git",
- "reference": "8041bc1960bf2da94e60b88b34e5c78300eac476"
+ "reference": "9277bd20262a01b38a33cc7356e98055f2262d32"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/icewind1991/SMB/zipball/8041bc1960bf2da94e60b88b34e5c78300eac476",
- "reference": "8041bc1960bf2da94e60b88b34e5c78300eac476",
+ "url": "https://api.github.com/repos/icewind1991/SMB/zipball/9277bd20262a01b38a33cc7356e98055f2262d32",
+ "reference": "9277bd20262a01b38a33cc7356e98055f2262d32",
"shasum": ""
},
"require": {
@@ -45,7 +45,7 @@
}
],
"description": "php wrapper for smbclient and libsmbclient-php",
- "time": "2015-04-20 11:16:24"
+ "time": "2015-08-17 14:20:38"
},
{
"name": "icewind/streams",
diff --git a/apps/files_external/3rdparty/composer/installed.json b/apps/files_external/3rdparty/composer/installed.json
index 42e8fdd29db..89c8ed56529 100644
--- a/apps/files_external/3rdparty/composer/installed.json
+++ b/apps/files_external/3rdparty/composer/installed.json
@@ -43,17 +43,17 @@
},
{
"name": "icewind/smb",
- "version": "v1.0.1",
- "version_normalized": "1.0.1.0",
+ "version": "v1.0.4",
+ "version_normalized": "1.0.4.0",
"source": {
"type": "git",
"url": "https://github.com/icewind1991/SMB.git",
- "reference": "8041bc1960bf2da94e60b88b34e5c78300eac476"
+ "reference": "9277bd20262a01b38a33cc7356e98055f2262d32"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/icewind1991/SMB/zipball/8041bc1960bf2da94e60b88b34e5c78300eac476",
- "reference": "8041bc1960bf2da94e60b88b34e5c78300eac476",
+ "url": "https://api.github.com/repos/icewind1991/SMB/zipball/9277bd20262a01b38a33cc7356e98055f2262d32",
+ "reference": "9277bd20262a01b38a33cc7356e98055f2262d32",
"shasum": ""
},
"require": {
@@ -63,7 +63,7 @@
"require-dev": {
"satooshi/php-coveralls": "dev-master"
},
- "time": "2015-04-20 11:16:24",
+ "time": "2015-08-17 14:20:38",
"type": "library",
"installation-source": "source",
"autoload": {
diff --git a/apps/files_external/3rdparty/icewind/smb/.travis.yml b/apps/files_external/3rdparty/icewind/smb/.travis.yml
deleted file mode 100644
index c1ac3727d08..00000000000
--- a/apps/files_external/3rdparty/icewind/smb/.travis.yml
+++ /dev/null
@@ -1,50 +0,0 @@
-language: php
-php:
- - 5.3
- - 5.4
- - 5.5
-
-env:
- global:
- - CURRENT_DIR=`pwd`
-
-before_install:
- - pass=$(perl -e 'print crypt("test", "password")')
- - sudo useradd -m -p $pass test
- - sudo apt-get update -qq
- - sudo apt-get install samba smbclient libsmbclient-dev libsmbclient
- - wget -O /tmp/libsmbclient-php.zip https://github.com/eduardok/libsmbclient-php/archive/master.zip
- - unzip /tmp/libsmbclient-php.zip -d /tmp
- - cd /tmp/libsmbclient-php-master
- - phpize && ./configure && make && sudo make install
- - echo 'extension="libsmbclient.so"' >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- - cd $CURRENT_DIR
- - chmod go+w $HOME
- - printf "%s\n%s\n" test test|sudo smbpasswd -s test
- - sudo mkdir /home/test/test
- - sudo chown test /home/test/test
- - |
- echo "[test]
- comment = test
- path = /home/test
- guest ok = yes
- writeable = yes
- map archive = yes
- map system = yes
- map hidden = yes
- create mask = 0777
- inherit permissions = yes" | sudo tee -a /etc/samba/smb.conf
- - sudo service smbd restart
- - testparm -s
-
-install:
- - composer install --dev --no-interaction
-
-script:
- - mkdir -p build/logs
- - cd tests
- - phpunit --coverage-clover ../build/logs/clover.xml --configuration phpunit.xml
-
-after_script:
- - cd $CURRENT_DIR
- - php vendor/bin/coveralls -v
diff --git a/apps/files_external/3rdparty/icewind/smb/src/AbstractShare.php b/apps/files_external/3rdparty/icewind/smb/src/AbstractShare.php
new file mode 100644
index 00000000000..a5cfe59a3c4
--- /dev/null
+++ b/apps/files_external/3rdparty/icewind/smb/src/AbstractShare.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * Copyright (c) 2015 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Licensed under the MIT license:
+ * http://opensource.org/licenses/MIT
+ */
+
+namespace Icewind\SMB;
+
+use Icewind\SMB\Exception\InvalidPathException;
+
+abstract class AbstractShare implements IShare {
+ private $forbiddenCharacters;
+
+ public function __construct() {
+ $this->forbiddenCharacters = array('?', '<', '>', ':', '*', '|', '"', chr(0), "\n", "\r");
+ }
+
+ protected function verifyPath($path) {
+ foreach ($this->forbiddenCharacters as $char) {
+ if (strpos($path, $char) !== false) {
+ throw new InvalidPathException('Invalid path, "' . $char . '" is not allowed');
+ }
+ }
+ }
+}
diff --git a/apps/files_external/3rdparty/icewind/smb/src/Connection.php b/apps/files_external/3rdparty/icewind/smb/src/Connection.php
index 6191b11ac8e..c857398c327 100644
--- a/apps/files_external/3rdparty/icewind/smb/src/Connection.php
+++ b/apps/files_external/3rdparty/icewind/smb/src/Connection.php
@@ -8,8 +8,10 @@
namespace Icewind\SMB;
use Icewind\SMB\Exception\AuthenticationException;
+use Icewind\SMB\Exception\ConnectException;
use Icewind\SMB\Exception\ConnectionException;
use Icewind\SMB\Exception\InvalidHostException;
+use Icewind\SMB\Exception\NoLoginServerException;
class Connection extends RawConnection {
const DELIMITER = 'smb:';
@@ -26,18 +28,25 @@ class Connection extends RawConnection {
/**
* get all unprocessed output from smbclient until the next prompt
*
- * @throws ConnectionException
* @return string
+ * @throws AuthenticationException
+ * @throws ConnectException
+ * @throws ConnectionException
+ * @throws InvalidHostException
+ * @throws NoLoginServerException
*/
public function read() {
if (!$this->isValid()) {
- throw new ConnectionException();
+ throw new ConnectionException('Connection not valid');
}
$line = $this->readLine(); //first line is prompt
$this->checkConnectionError($line);
$output = array();
$line = $this->readLine();
+ if ($line === false) {
+ throw new ConnectException('Unknown error');
+ }
$length = mb_strlen(self::DELIMITER);
while (mb_substr($line, 0, $length) !== self::DELIMITER) { //next prompt functions as delimiter
$output[] .= $line;
@@ -52,20 +61,24 @@ class Connection extends RawConnection {
* @param $line
* @throws AuthenticationException
* @throws InvalidHostException
+ * @throws NoLoginServerException
*/
private function checkConnectionError($line) {
$line = rtrim($line, ')');
if (substr($line, -23) === ErrorCodes::LogonFailure) {
- throw new AuthenticationException();
+ throw new AuthenticationException('Invalid login');
}
if (substr($line, -26) === ErrorCodes::BadHostName) {
- throw new InvalidHostException();
+ throw new InvalidHostException('Invalid hostname');
}
if (substr($line, -22) === ErrorCodes::Unsuccessful) {
- throw new InvalidHostException();
+ throw new InvalidHostException('Connection unsuccessful');
}
if (substr($line, -28) === ErrorCodes::ConnectionRefused) {
- throw new InvalidHostException();
+ throw new InvalidHostException('Connection refused');
+ }
+ if (substr($line, -26) === ErrorCodes::NoLogonServers) {
+ throw new NoLoginServerException('No login server');
}
}
diff --git a/apps/files_external/3rdparty/icewind/smb/src/ErrorCodes.php b/apps/files_external/3rdparty/icewind/smb/src/ErrorCodes.php
index d9f2507cba9..03bd574c185 100644
--- a/apps/files_external/3rdparty/icewind/smb/src/ErrorCodes.php
+++ b/apps/files_external/3rdparty/icewind/smb/src/ErrorCodes.php
@@ -15,6 +15,7 @@ class ErrorCodes {
const BadHostName = 'NT_STATUS_BAD_NETWORK_NAME';
const Unsuccessful = 'NT_STATUS_UNSUCCESSFUL';
const ConnectionRefused = 'NT_STATUS_CONNECTION_REFUSED';
+ const NoLogonServers = 'NT_STATUS_NO_LOGON_SERVERS';
const PathNotFound = 'NT_STATUS_OBJECT_PATH_NOT_FOUND';
const NoSuchFile = 'NT_STATUS_NO_SUCH_FILE';
diff --git a/apps/files_external/3rdparty/icewind/smb/src/Exception/InvalidPathException.php b/apps/files_external/3rdparty/icewind/smb/src/Exception/InvalidPathException.php
new file mode 100644
index 00000000000..4bba74f269f
--- /dev/null
+++ b/apps/files_external/3rdparty/icewind/smb/src/Exception/InvalidPathException.php
@@ -0,0 +1,10 @@
+<?php
+/**
+ * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Licensed under the MIT license:
+ * http://opensource.org/licenses/MIT
+ */
+
+namespace Icewind\SMB\Exception;
+
+class InvalidPathException extends InvalidRequestException {}
diff --git a/apps/files_external/3rdparty/icewind/smb/tests/bootstrap.php b/apps/files_external/3rdparty/icewind/smb/src/Exception/NoLoginServerException.php
index dc2e34b183e..43f7f9aeff9 100644
--- a/apps/files_external/3rdparty/icewind/smb/tests/bootstrap.php
+++ b/apps/files_external/3rdparty/icewind/smb/src/Exception/NoLoginServerException.php
@@ -5,5 +5,6 @@
* http://opensource.org/licenses/MIT
*/
-date_default_timezone_set('UTC');
-require_once __DIR__.'/../vendor/autoload.php';
+namespace Icewind\SMB\Exception;
+
+class NoLoginServerException extends ConnectException {}
diff --git a/apps/files_external/3rdparty/icewind/smb/src/NativeServer.php b/apps/files_external/3rdparty/icewind/smb/src/NativeServer.php
index 4628e3ec108..ce8e6d636a9 100644
--- a/apps/files_external/3rdparty/icewind/smb/src/NativeServer.php
+++ b/apps/files_external/3rdparty/icewind/smb/src/NativeServer.php
@@ -24,12 +24,7 @@ class NativeServer extends Server {
}
protected function connect() {
- $user = $this->getUser();
- $workgroup = null;
- if (strpos($user, '/')) {
- list($workgroup, $user) = explode($user, '/');
- }
- $this->state->init($workgroup, $user, $this->getPassword());
+ $this->state->init($this->getWorkgroup(), $this->getUser(), $this->getPassword());
}
/**
diff --git a/apps/files_external/3rdparty/icewind/smb/src/NativeShare.php b/apps/files_external/3rdparty/icewind/smb/src/NativeShare.php
index c84e9611667..1f1d225c00a 100644
--- a/apps/files_external/3rdparty/icewind/smb/src/NativeShare.php
+++ b/apps/files_external/3rdparty/icewind/smb/src/NativeShare.php
@@ -7,7 +7,7 @@
namespace Icewind\SMB;
-class NativeShare implements IShare {
+class NativeShare extends AbstractShare {
/**
* @var Server $server
*/
@@ -28,6 +28,7 @@ class NativeShare implements IShare {
* @param string $name
*/
public function __construct($server, $name) {
+ parent::__construct();
$this->server = $server;
$this->name = $name;
$this->state = new NativeState();
@@ -43,15 +44,7 @@ class NativeShare implements IShare {
return;
}
- $user = $this->server->getUser();
- if (strpos($user, '/')) {
- list($workgroup, $user) = explode('/', $user);
- } elseif (strpos($user, '\\')) {
- list($workgroup, $user) = explode('\\', $user);
- } else {
- $workgroup = null;
- }
- $this->state->init($workgroup, $user, $this->server->getPassword());
+ $this->state->init($this->server->getWorkgroup(), $this->server->getUser(), $this->server->getPassword());
}
/**
@@ -64,6 +57,7 @@ class NativeShare implements IShare {
}
private function buildUrl($path) {
+ $this->verifyPath($path);
$url = sprintf('smb://%s/%s', $this->server->getHost(), $this->name);
if ($path) {
$path = trim($path, '/');
@@ -149,6 +143,7 @@ class NativeShare implements IShare {
* @throws \Icewind\SMB\Exception\InvalidTypeException
*/
public function del($path) {
+ $this->connect();
return $this->state->unlink($this->buildUrl($path));
}
diff --git a/apps/files_external/3rdparty/icewind/smb/src/Server.php b/apps/files_external/3rdparty/icewind/smb/src/Server.php
index f7227d4baef..bbc0475d5e4 100644
--- a/apps/files_external/3rdparty/icewind/smb/src/Server.php
+++ b/apps/files_external/3rdparty/icewind/smb/src/Server.php
@@ -30,6 +30,11 @@ class Server {
protected $password;
/**
+ * @var string $workgroup
+ */
+ protected $workgroup;
+
+ /**
* Check if the smbclient php extension is available
*
* @return bool
@@ -45,11 +50,29 @@ class Server {
*/
public function __construct($host, $user, $password) {
$this->host = $host;
+ list($workgroup, $user) = $this->splitUser($user);
$this->user = $user;
+ $this->workgroup = $workgroup;
$this->password = $password;
}
/**
+ * Split workgroup from username
+ *
+ * @param $user
+ * @return string[] [$workgroup, $user]
+ */
+ public function splitUser($user) {
+ if (strpos($user, '/')) {
+ return explode('/', $user, 2);
+ } elseif (strpos($user, '\\')) {
+ return explode('\\', $user);
+ } else {
+ return array(null, $user);
+ }
+ }
+
+ /**
* @return string
*/
public function getAuthString() {
@@ -78,13 +101,21 @@ class Server {
}
/**
+ * @return string
+ */
+ public function getWorkgroup() {
+ return $this->workgroup;
+ }
+
+ /**
* @return \Icewind\SMB\IShare[]
*
* @throws \Icewind\SMB\Exception\AuthenticationException
* @throws \Icewind\SMB\Exception\InvalidHostException
*/
public function listShares() {
- $command = Server::CLIENT . ' --authentication-file=/proc/self/fd/3' .
+ $workgroupArgument = ($this->workgroup) ? ' -W ' . escapeshellarg($this->workgroup) : '';
+ $command = Server::CLIENT . $workgroupArgument . ' --authentication-file=/proc/self/fd/3' .
' -gL ' . escapeshellarg($this->getHost());
$connection = new RawConnection($command);
$connection->writeAuthentication($this->getUser(), $this->getPassword());
diff --git a/apps/files_external/3rdparty/icewind/smb/src/Share.php b/apps/files_external/3rdparty/icewind/smb/src/Share.php
index 7c24f9f2e90..d9ab729025d 100644
--- a/apps/files_external/3rdparty/icewind/smb/src/Share.php
+++ b/apps/files_external/3rdparty/icewind/smb/src/Share.php
@@ -7,17 +7,13 @@
namespace Icewind\SMB;
-use Icewind\SMB\Exception\AccessDeniedException;
-use Icewind\SMB\Exception\AlreadyExistsException;
use Icewind\SMB\Exception\ConnectionException;
-use Icewind\SMB\Exception\Exception;
use Icewind\SMB\Exception\FileInUseException;
use Icewind\SMB\Exception\InvalidTypeException;
-use Icewind\SMB\Exception\NotEmptyException;
use Icewind\SMB\Exception\NotFoundException;
use Icewind\Streams\CallbackWrapper;
-class Share implements IShare {
+class Share extends AbstractShare {
/**
* @var Server $server
*/
@@ -43,6 +39,7 @@ class Share implements IShare {
* @param string $name
*/
public function __construct($server, $name) {
+ parent::__construct();
$this->server = $server;
$this->name = $name;
$this->parser = new Parser(new TimeZoneProvider($this->server->getHost()));
@@ -57,10 +54,11 @@ class Share implements IShare {
if ($this->connection and $this->connection->isValid()) {
return;
}
- $command = sprintf('%s --authentication-file=/proc/self/fd/3 //%s/%s',
+ $workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : '';
+ $command = sprintf('%s %s --authentication-file=/proc/self/fd/3 %s',
Server::CLIENT,
- $this->server->getHost(),
- $this->name
+ $workgroupArgument,
+ escapeshellarg('//' . $this->server->getHost() . '/' . $this->name)
);
$this->connection = new Connection($command);
$this->connection->writeAuthentication($this->server->getUser(), $this->server->getPassword());
@@ -256,18 +254,18 @@ class Share implements IShare {
*/
public function read($source) {
$source = $this->escapePath($source);
- // close the single quote, open a double quote where we put the single quote...
- $source = str_replace('\'', '\'"\'"\'', $source);
// since returned stream is closed by the caller we need to create a new instance
// since we can't re-use the same file descriptor over multiple calls
- $command = sprintf('%s --authentication-file=/proc/self/fd/3 //%s/%s -c \'get %s /proc/self/fd/5\'',
+ $workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : '';
+ $command = sprintf('%s %s --authentication-file=/proc/self/fd/3 %s',
Server::CLIENT,
- $this->server->getHost(),
- $this->name,
- $source
+ $workgroupArgument,
+ escapeshellarg('//' . $this->server->getHost() . '/' . $this->name)
);
$connection = new Connection($command);
$connection->writeAuthentication($this->server->getUser(), $this->server->getPassword());
+ $connection->write('get ' . $source . ' /proc/self/fd/5');
+ $connection->write('exit');
$fh = $connection->getFileOutputStream();
stream_context_set_option($fh, 'file', 'connection', $connection);
return $fh;
@@ -284,23 +282,24 @@ class Share implements IShare {
*/
public function write($target) {
$target = $this->escapePath($target);
- // close the single quote, open a double quote where we put the single quote...
- $target = str_replace('\'', '\'"\'"\'', $target);
// since returned stream is closed by the caller we need to create a new instance
// since we can't re-use the same file descriptor over multiple calls
- $command = sprintf('%s --authentication-file=/proc/self/fd/3 //%s/%s -c \'put /proc/self/fd/4 %s\'',
+ $workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : '';
+ $command = sprintf('%s %s --authentication-file=/proc/self/fd/3 %s',
Server::CLIENT,
- $this->server->getHost(),
- $this->name,
- $target
+ $workgroupArgument,
+ escapeshellarg('//' . $this->server->getHost() . '/' . $this->name)
);
- $connection = new RawConnection($command);
+ $connection = new Connection($command);
$connection->writeAuthentication($this->server->getUser(), $this->server->getPassword());
$fh = $connection->getFileInputStream();
+ $connection->write('put /proc/self/fd/4 ' . $target);
+ $connection->write('exit');
+
// use a close callback to ensure the upload is finished before continuing
// this also serves as a way to keep the connection in scope
- return CallbackWrapper::wrap($fh, null, null, function () use ($connection) {
+ return CallbackWrapper::wrap($fh, null, null, function () use ($connection, $target) {
$connection->close(false); // dont terminate, give the upload some time
});
}
@@ -378,6 +377,7 @@ class Share implements IShare {
* @return string
*/
protected function escapePath($path) {
+ $this->verifyPath($path);
if ($path === '/') {
$path = '';
}
diff --git a/apps/files_external/3rdparty/icewind/smb/tests/AbstractShare.php b/apps/files_external/3rdparty/icewind/smb/tests/AbstractShare.php
deleted file mode 100644
index f8ccb7119ed..00000000000
--- a/apps/files_external/3rdparty/icewind/smb/tests/AbstractShare.php
+++ /dev/null
@@ -1,539 +0,0 @@
-<?php
-/**
- * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Licensed under the MIT license:
- * http://opensource.org/licenses/MIT
- */
-
-namespace Icewind\SMB\Test;
-
-use Icewind\SMB\FileInfo;
-
-abstract class AbstractShare extends \PHPUnit_Framework_TestCase {
- /**
- * @var \Icewind\SMB\Server $server
- */
- protected $server;
-
- /**
- * @var \Icewind\SMB\IShare $share
- */
- protected $share;
-
- /**
- * @var string $root
- */
- protected $root;
-
- protected $config;
-
- public function tearDown() {
- try {
- if ($this->share) {
- $this->cleanDir($this->root);
- }
- unset($this->share);
- } catch (\Exception $e) {
- unset($this->share);
- throw $e;
- }
- }
-
- public function nameProvider() {
- // / ? < > \ : * | " are illegal characters in path on windows
- return array(
- array('simple'),
- array('with spaces_and-underscores'),
- array("single'quote'"),
- array('日本語'),
- array('url %2F +encode'),
- array('a somewhat longer filename than the other with more charaters as the all the other filenames'),
- array('$as#d€££Ö€ßœĚęĘĞĜΣΥΦΩΫ')
- );
- }
-
- public function fileDataProvider() {
- return array(
- array('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua'),
- array('Mixed language, 日本語 が わからか and Various _/* characters \\|” €')
- );
- }
-
- public function nameAndDataProvider() {
- $names = $this->nameProvider();
- $data = $this->fileDataProvider();
- $result = array();
- foreach ($names as $name) {
- foreach ($data as $text) {
- $result[] = array($name[0], $text[0]);
- }
- }
- return $result;
- }
-
- public function cleanDir($dir) {
- $content = $this->share->dir($dir);
- foreach ($content as $metadata) {
- if ($metadata->isDirectory()) {
- $this->cleanDir($metadata->getPath());
- } else {
- $this->share->del($metadata->getPath());
- }
- }
- $this->share->rmdir($dir);
- }
-
- private function getTextFile($text = '') {
- if (!$text) {
- $text = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua';
- }
- $file = tempnam('/tmp', 'smb_test_');
- file_put_contents($file, $text);
- return $file;
- }
-
- public function testListShares() {
- $shares = $this->server->listShares();
- foreach ($shares as $share) {
- if ($share->getName() === $this->config->share) {
- return;
- }
- }
- $this->fail('Share "' . $this->config->share . '" not found');
- }
-
- public function testRootStartsEmpty() {
- $this->assertEquals(array(), $this->share->dir($this->root));
- }
-
- /**
- * @dataProvider nameProvider
- */
- public function testMkdir($name) {
- $this->share->mkdir($this->root . '/' . $name);
- $dirs = $this->share->dir($this->root);
- $this->assertCount(1, $dirs);
- $this->assertEquals($name, $dirs[0]->getName());
- $this->assertTrue($dirs[0]->isDirectory());
- }
-
- /**
- * @dataProvider nameProvider
- */
- public function testRenameDirectory($name) {
- $this->share->mkdir($this->root . '/' . $name);
- $this->share->rename($this->root . '/' . $name, $this->root . '/' . $name . '_rename');
- $dirs = $this->share->dir($this->root);
- $this->assertEquals(1, count($dirs));
- $this->assertEquals($name . '_rename', $dirs[0]->getName());
- }
-
- /**
- * @dataProvider nameProvider
- */
- public function testRmdir($name) {
- $this->share->mkdir($this->root . '/' . $name);
- $this->share->rmdir($this->root . '/' . $name);
- $this->assertCount(0, $this->share->dir($this->root));
- }
-
- /**
- * @dataProvider nameAndDataProvider
- */
- public function testPut($name, $text) {
- $tmpFile = $this->getTextFile($text);
- $size = filesize($tmpFile);
-
- $this->share->put($tmpFile, $this->root . '/' . $name);
- unlink($tmpFile);
-
- $files = $this->share->dir($this->root);
- $this->assertCount(1, $files);
- $this->assertEquals($name, $files[0]->getName());
- $this->assertEquals($size, $files[0]->getSize());
- $this->assertFalse($files[0]->isDirectory());
- }
-
- /**
- * @dataProvider nameProvider
- */
- public function testRenameFile($name) {
- $tmpFile = $this->getTextFile();
-
- $this->share->put($tmpFile, $this->root . '/' . $name);
- unlink($tmpFile);
-
- $this->share->rename($this->root . '/' . $name, $this->root . '/' . $name . '_renamed');
-
- $files = $this->share->dir($this->root);
- $this->assertEquals(1, count($files));
- $this->assertEquals($name . '_renamed', $files[0]->getName());
- }
-
- /**
- * @dataProvider nameAndDataProvider
- */
- public function testGet($name, $text) {
- $tmpFile = $this->getTextFile($text);
-
- $this->share->put($tmpFile, $this->root . '/' . $name);
- unlink($tmpFile);
-
- $targetFile = tempnam('/tmp', 'smb_test_');
- $this->share->get($this->root . '/' . $name, $targetFile);
-
- $this->assertEquals($text, file_get_contents($targetFile));
- unlink($targetFile);
- }
-
- /**
- * @dataProvider nameProvider
- */
- public function testDel($name) {
- $tmpFile = $this->getTextFile();
-
- $this->share->put($tmpFile, $this->root . '/' . $name);
- unlink($tmpFile);
-
- $this->share->del($this->root . '/' . $name);
- $this->assertCount(0, $this->share->dir($this->root));
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\NotFoundException
- */
- public function testCreateFolderInNonExistingFolder() {
- $this->share->mkdir($this->root . '/foo/bar');
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\NotFoundException
- */
- public function testRemoveFolderInNonExistingFolder() {
- $this->share->rmdir($this->root . '/foo/bar');
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\NotFoundException
- */
- public function testRemoveNonExistingFolder() {
- $this->share->rmdir($this->root . '/foo');
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\AlreadyExistsException
- */
- public function testCreateExistingFolder() {
- $this->share->mkdir($this->root . '/bar');
- $this->share->mkdir($this->root . '/bar');
- $this->share->rmdir($this->root . '/bar');
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\InvalidTypeException
- */
- public function testCreateFileExistingFolder() {
- $this->share->mkdir($this->root . '/bar');
- $this->share->put($this->getTextFile(), $this->root . '/bar');
- $this->share->rmdir($this->root . '/bar');
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\NotFoundException
- */
- public function testCreateFileInNonExistingFolder() {
- $this->share->put($this->getTextFile(), $this->root . '/foo/bar');
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\NotFoundException
- */
- public function testTestRemoveNonExistingFile() {
- $this->share->del($this->root . '/foo');
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\NotFoundException
- */
- public function testDownloadNonExistingFile() {
- $this->share->get($this->root . '/foo', '/dev/null');
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\InvalidTypeException
- */
- public function testDownloadFolder() {
- $this->share->mkdir($this->root . '/foobar');
- $this->share->get($this->root . '/foobar', '/dev/null');
- $this->share->rmdir($this->root . '/foobar');
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\InvalidTypeException
- */
- public function testDelFolder() {
- $this->share->mkdir($this->root . '/foobar');
- $this->share->del($this->root . '/foobar');
- $this->share->rmdir($this->root . '/foobar');
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\InvalidTypeException
- */
- public function testRmdirFile() {
- $this->share->put($this->getTextFile(), $this->root . '/foobar');
- $this->share->rmdir($this->root . '/foobar');
- $this->share->del($this->root . '/foobar');
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\NotEmptyException
- */
- public function testRmdirNotEmpty() {
- $this->share->mkdir($this->root . '/foobar');
- $this->share->put($this->getTextFile(), $this->root . '/foobar/asd');
- $this->share->rmdir($this->root . '/foobar');
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\NotFoundException
- */
- public function testDirNonExisting() {
- $this->share->dir('/foobar/asd');
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\NotFoundException
- */
- public function testRmDirNonExisting() {
- $this->share->rmdir('/foobar/asd');
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\NotFoundException
- */
- public function testRenameNonExisting() {
- $this->share->rename('/foobar/asd', '/foobar/bar');
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\NotFoundException
- */
- public function testRenameTargetNonExisting() {
- $txt = $this->getTextFile();
- $this->share->put($txt, $this->root . '/foo.txt');
- unlink($txt);
- $this->share->rename($this->root . '/foo.txt', $this->root . '/bar/foo.txt');
- }
-
- public function testModifiedDate() {
- $now = time();
- $this->share->put($this->getTextFile(), $this->root . '/foo.txt');
- $dir = $this->share->dir($this->root);
- $mtime = $dir[0]->getMTime();
- $this->assertTrue(abs($now - $mtime) <= 2, 'Modified time differs by ' . abs($now - $mtime) . ' seconds');
- $this->share->del($this->root . '/foo.txt');
- }
-
- /**
- * @dataProvider nameAndDataProvider
- */
- public function testReadStream($name, $text) {
- $sourceFile = $this->getTextFile($text);
- $this->share->put($sourceFile, $this->root . '/' . $name);
- $fh = $this->share->read($this->root . '/' . $name);
- $content = stream_get_contents($fh);
- fclose($fh);
- $this->share->del($this->root . '/' . $name);
-
- $this->assertEquals(file_get_contents($sourceFile), $content);
- }
-
- /**
- * @dataProvider nameAndDataProvider
- */
- public function testWriteStream($name, $text) {
- $fh = $this->share->write($this->root . '/' . $name);
- fwrite($fh, $text);
- fclose($fh);
-
- $tmpFile1 = tempnam('/tmp', 'smb_test_');
- $this->share->get($this->root . '/' . $name, $tmpFile1);
- $this->assertEquals($text, file_get_contents($tmpFile1));
- $this->share->del($this->root . '/' . $name);
- unlink($tmpFile1);
- }
-
- public function testDir() {
- $txtFile = $this->getTextFile();
-
- $this->share->mkdir($this->root . '/dir');
- $this->share->put($txtFile, $this->root . '/file.txt');
- unlink($txtFile);
-
- $dir = $this->share->dir($this->root);
- if ($dir[0]->getName() === 'dir') {
- $dirEntry = $dir[0];
- } else {
- $dirEntry = $dir[1];
- }
- $this->assertTrue($dirEntry->isDirectory());
- $this->assertFalse($dirEntry->isReadOnly());
- $this->assertFalse($dirEntry->isReadOnly());
-
- if ($dir[0]->getName() === 'file.txt') {
- $fileEntry = $dir[0];
- } else {
- $fileEntry = $dir[1];
- }
- $this->assertFalse($fileEntry->isDirectory());
- $this->assertFalse($fileEntry->isReadOnly());
- $this->assertFalse($fileEntry->isReadOnly());
- }
-
- /**
- * @dataProvider nameProvider
- */
- public function testStat($name) {
- $txtFile = $this->getTextFile();
- $size = filesize($txtFile);
-
- $this->share->put($txtFile, $this->root . '/' . $name);
- unlink($txtFile);
-
- $info = $this->share->stat($this->root . '/' . $name);
- $this->assertEquals($size, $info->getSize());
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\NotFoundException
- */
- public function testStatNonExisting() {
- $this->share->stat($this->root . '/fo.txt');
- }
-
- /**
- * note setting archive and system bit is not supported
- *
- * @dataProvider nameProvider
- */
- public function testSetMode($name) {
- $txtFile = $this->getTextFile();
-
- $this->share->put($txtFile, $this->root . '/' . $name);
-
- $this->share->setMode($this->root . '/' . $name, FileInfo::MODE_NORMAL);
- $info = $this->share->stat($this->root . '/' . $name);
- $this->assertFalse($info->isReadOnly());
- $this->assertFalse($info->isArchived());
- $this->assertFalse($info->isSystem());
- $this->assertFalse($info->isHidden());
-
- $this->share->setMode($this->root . '/' . $name, FileInfo::MODE_READONLY);
- $info = $this->share->stat($this->root . '/' . $name);
- $this->assertTrue($info->isReadOnly());
- $this->assertFalse($info->isArchived());
- $this->assertFalse($info->isSystem());
- $this->assertFalse($info->isHidden());
-
- $this->share->setMode($this->root . '/' . $name, FileInfo::MODE_ARCHIVE);
- $info = $this->share->stat($this->root . '/' . $name);
- $this->assertFalse($info->isReadOnly());
- $this->assertTrue($info->isArchived());
- $this->assertFalse($info->isSystem());
- $this->assertFalse($info->isHidden());
-
- $this->share->setMode($this->root . '/' . $name, FileInfo::MODE_READONLY | FileInfo::MODE_ARCHIVE);
- $info = $this->share->stat($this->root . '/' . $name);
- $this->assertTrue($info->isReadOnly());
- $this->assertTrue($info->isArchived());
- $this->assertFalse($info->isSystem());
- $this->assertFalse($info->isHidden());
-
- $this->share->setMode($this->root . '/' . $name, FileInfo::MODE_HIDDEN);
- $info = $this->share->stat($this->root . '/' . $name);
- $this->assertFalse($info->isReadOnly());
- $this->assertFalse($info->isArchived());
- $this->assertFalse($info->isSystem());
- $this->assertTrue($info->isHidden());
-
- $this->share->setMode($this->root . '/' . $name, FileInfo::MODE_SYSTEM);
- $info = $this->share->stat($this->root . '/' . $name);
- $this->assertFalse($info->isReadOnly());
- $this->assertFalse($info->isArchived());
- $this->assertTrue($info->isSystem());
- $this->assertFalse($info->isHidden());
-
- $this->share->setMode($this->root . '/' . $name, FileInfo::MODE_NORMAL);
- $info = $this->share->stat($this->root . '/' . $name);
- $this->assertFalse($info->isReadOnly());
- $this->assertFalse($info->isArchived());
- $this->assertFalse($info->isSystem());
- $this->assertFalse($info->isHidden());
- }
-
- public function pathProvider() {
- // / ? < > \ : * | " are illegal characters in path on windows
- return array(
- array('dir/sub/foo.txt'),
- array('bar.txt'),
- array("single'quote'/sub/foo.txt"),
- array('日本語/url %2F +encode/asd.txt'),
- array(
- 'a somewhat longer folder than the other with more charaters as the all the other filenames/' .
- 'followed by a somewhat long file name after that.txt'
- )
- );
- }
-
- /**
- * @dataProvider pathProvider
- */
- public function testSubDirs($path) {
- $dirs = explode('/', $path);
- $name = array_pop($dirs);
- $fullPath = '';
- foreach ($dirs as $dir) {
- $fullPath .= '/' . $dir;
- $this->share->mkdir($this->root . $fullPath);
- }
- $txtFile = $this->getTextFile();
- $size = filesize($txtFile);
- $this->share->put($txtFile, $this->root . $fullPath . '/' . $name);
- unlink($txtFile);
- $info = $this->share->stat($this->root . $fullPath . '/' . $name);
- $this->assertEquals($size, $info->getSize());
- $this->assertFalse($info->isHidden());
- }
-
- public function testDelAfterStat() {
- $name = 'foo.txt';
- $txtFile = $this->getTextFile();
-
- $this->share->put($txtFile, $this->root . '/' . $name);
- unlink($txtFile);
-
- $this->share->stat($this->root . '/' . $name);
- $this->share->del($this->root . '/foo.txt');
- }
-
- /**
- * @param $name
- * @dataProvider nameProvider
- */
- public function testDirPaths($name) {
- $txtFile = $this->getTextFile();
- $this->share->mkdir($this->root . '/' . $name);
- $this->share->put($txtFile, $this->root . '/' . $name . '/' . $name);
- unlink($txtFile);
-
- $content = $this->share->dir($this->root . '/' . $name);
- $this->assertCount(1, $content);
- $this->assertEquals($name, $content[0]->getName());
- }
-
- public function testStatRoot() {
- $info = $this->share->stat('/');
- $this->assertInstanceOf('\Icewind\SMB\IFileInfo', $info);
- }
-}
diff --git a/apps/files_external/3rdparty/icewind/smb/tests/NativeShare.php b/apps/files_external/3rdparty/icewind/smb/tests/NativeShare.php
deleted file mode 100644
index d8e10235c12..00000000000
--- a/apps/files_external/3rdparty/icewind/smb/tests/NativeShare.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-/**
- * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Licensed under the MIT license:
- * http://opensource.org/licenses/MIT
- */
-
-namespace Icewind\SMB\Test;
-
-use Icewind\SMB\NativeServer;
-
-class NativeShare extends AbstractShare {
- public function setUp() {
- if (!function_exists('smbclient_state_new')) {
- $this->markTestSkipped('libsmbclient php extension not installed');
- }
- $this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
- $this->server = new NativeServer($this->config->host, $this->config->user, $this->config->password);
- $this->share = $this->server->getShare($this->config->share);
- if ($this->config->root) {
- $this->root = '/' . $this->config->root . '/' . uniqid();
- } else {
- $this->root = '/' . uniqid();
- }
- $this->share->mkdir($this->root);
- }
-}
diff --git a/apps/files_external/3rdparty/icewind/smb/tests/NativeStream.php b/apps/files_external/3rdparty/icewind/smb/tests/NativeStream.php
deleted file mode 100644
index 2d7b62fedeb..00000000000
--- a/apps/files_external/3rdparty/icewind/smb/tests/NativeStream.php
+++ /dev/null
@@ -1,143 +0,0 @@
-<?php
-/**
- * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Licensed under the MIT license:
- * http://opensource.org/licenses/MIT
- */
-
-namespace Icewind\SMB\Test;
-
-use Icewind\SMB\NativeServer;
-
-class NativeStream extends \PHPUnit_Framework_TestCase {
- /**
- * @var \Icewind\SMB\Server $server
- */
- protected $server;
-
- /**
- * @var \Icewind\SMB\NativeShare $share
- */
- protected $share;
-
- /**
- * @var string $root
- */
- protected $root;
-
- protected $config;
-
- public function setUp() {
- if (!function_exists('smbclient_state_new')) {
- $this->markTestSkipped('libsmbclient php extension not installed');
- }
- $this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
- $this->server = new NativeServer($this->config->host, $this->config->user, $this->config->password);
- $this->share = $this->server->getShare($this->config->share);
- if ($this->config->root) {
- $this->root = '/' . $this->config->root . '/' . uniqid();
- } else {
- $this->root = '/' . uniqid();
- }
- $this->share->mkdir($this->root);
- }
-
- private function getTextFile() {
- $text = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua';
- $file = tempnam('/tmp', 'smb_test_');
- file_put_contents($file, $text);
- return $file;
- }
-
- public function testSeekTell() {
- $sourceFile = $this->getTextFile();
- $this->share->put($sourceFile, $this->root . '/foobar');
- $fh = $this->share->read($this->root . '/foobar');
- $content = fread($fh, 3);
- $this->assertEquals('Lor', $content);
-
- fseek($fh, -2, SEEK_CUR);
-
- $content = fread($fh, 3);
- $this->assertEquals('ore', $content);
-
- fseek($fh, 3, SEEK_SET);
-
- $content = fread($fh, 3);
- $this->assertEquals('em ', $content);
-
- fseek($fh, -3, SEEK_END);
-
- $content = fread($fh, 3);
- $this->assertEquals('qua', $content);
-
- fseek($fh, -3, SEEK_END);
- $this->assertEquals(120, ftell($fh));
- }
-
- public function testStat() {
- $sourceFile = $this->getTextFile();
- $this->share->put($sourceFile, $this->root . '/foobar');
- $fh = $this->share->read($this->root . '/foobar');
- $stat = fstat($fh);
- $this->assertEquals(filesize($sourceFile), $stat['size']);
- unlink($sourceFile);
- }
-
- public function testTruncate() {
- if (version_compare(phpversion(), '5.4.0', '<')) {
- $this->markTestSkipped('php <5.4 doesn\'t support truncate for stream wrappers');
- }
- $fh = $this->share->write($this->root . '/foobar');
- fwrite($fh, 'foobar');
- ftruncate($fh, 3);
- fclose($fh);
-
- $fh = $this->share->read($this->root . '/foobar');
- $this->assertEquals('foo', stream_get_contents($fh));
- }
-
- public function testEOF() {
- if (version_compare(phpversion(), '5.4.0', '<')) {
- $this->markTestSkipped('php <5.4 doesn\'t support truncate for stream wrappers');
- }
- $fh = $this->share->write($this->root . '/foobar');
- fwrite($fh, 'foobar');
- fclose($fh);
-
- $fh = $this->share->read($this->root . '/foobar');
- fread($fh, 3);
- $this->assertFalse(feof($fh));
- fread($fh, 5);
- $this->assertTrue(feof($fh));
- }
-
- public function testLockUnsupported() {
- $fh = $this->share->write($this->root . '/foobar');
- $this->assertFalse(flock($fh, LOCK_SH));
- }
-
- public function testSetOptionUnsupported() {
- $fh = $this->share->write($this->root . '/foobar');
- $this->assertFalse(stream_set_blocking($fh, false));
- }
-
- public function tearDown() {
- if ($this->share) {
- $this->cleanDir($this->root);
- }
- unset($this->share);
- }
-
- public function cleanDir($dir) {
- $content = $this->share->dir($dir);
- foreach ($content as $metadata) {
- if ($metadata->isDirectory()) {
- $this->cleanDir($metadata->getPath());
- } else {
- $this->share->del($metadata->getPath());
- }
- }
- $this->share->rmdir($dir);
- }
-}
diff --git a/apps/files_external/3rdparty/icewind/smb/tests/Parser.php b/apps/files_external/3rdparty/icewind/smb/tests/Parser.php
deleted file mode 100644
index 5caa048a664..00000000000
--- a/apps/files_external/3rdparty/icewind/smb/tests/Parser.php
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-/**
- * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Licensed under the MIT license:
- * http://opensource.org/licenses/MIT
- */
-
-namespace Icewind\SMB\Test;
-
-
-use Icewind\SMB\FileInfo;
-
-class Parser extends \PHPUnit_Framework_TestCase {
- public function modeProvider() {
- return array(
- array('D', FileInfo::MODE_DIRECTORY),
- array('A', FileInfo::MODE_ARCHIVE),
- array('S', FileInfo::MODE_SYSTEM),
- array('H', FileInfo::MODE_HIDDEN),
- array('R', FileInfo::MODE_READONLY),
- array('N', FileInfo::MODE_NORMAL),
- array('RA', FileInfo::MODE_READONLY | FileInfo::MODE_ARCHIVE),
- array('RAH', FileInfo::MODE_READONLY | FileInfo::MODE_ARCHIVE | FileInfo::MODE_HIDDEN)
- );
- }
-
- /**
- * @param string $timeZone
- * @return \Icewind\SMB\TimeZoneProvider
- */
- private function getTimeZoneProvider($timeZone) {
- $mock = $this->getMockBuilder('\Icewind\SMB\TimeZoneProvider')
- ->disableOriginalConstructor()
- ->getMock();
- $mock->expects($this->any())
- ->method('get')
- ->will($this->returnValue($timeZone));
- return $mock;
- }
-
- /**
- * @dataProvider modeProvider
- */
- public function testParseMode($string, $mode) {
- $parser = new \Icewind\SMB\Parser($this->getTimeZoneProvider('UTC'));
- $this->assertEquals($mode, $parser->parseMode($string), 'Failed parsing ' . $string);
- }
-
- public function statProvider() {
- return array(
- array(
- array(
- 'altname: test.txt',
- 'create_time: Sat Oct 12 07:05:58 PM 2013 CEST',
- 'access_time: Tue Oct 15 02:58:48 PM 2013 CEST',
- 'write_time: Sat Oct 12 07:05:58 PM 2013 CEST',
- 'change_time: Sat Oct 12 07:05:58 PM 2013 CEST',
- 'attributes: (80)',
- 'stream: [::$DATA], 29634 bytes'
- ),
- array(
- 'mtime' => strtotime('12 Oct 2013 19:05:58 CEST'),
- 'mode' => FileInfo::MODE_NORMAL,
- 'size' => 29634
- )
- )
- );
- }
-
- /**
- * @dataProvider statProvider
- */
- public function testStat($output, $stat) {
- $parser = new \Icewind\SMB\Parser($this->getTimeZoneProvider('UTC'));
- $this->assertEquals($stat, $parser->parseStat($output));
- }
-
- public function dirProvider() {
- return array(
- array(
- array(
- ' . D 0 Tue Aug 26 19:11:56 2014',
- ' .. DR 0 Sun Oct 28 15:24:02 2012',
- ' c.pdf N 29634 Sat Oct 12 19:05:58 2013',
- '',
- ' 62536 blocks of size 8388608. 57113 blocks available'
- ),
- array(
- new FileInfo('/c.pdf', 'c.pdf', 29634, strtotime('12 Oct 2013 19:05:58 CEST'),
- FileInfo::MODE_NORMAL)
- )
- )
- );
- }
-
- /**
- * @dataProvider dirProvider
- */
- public function testDir($output, $dir) {
- $parser = new \Icewind\SMB\Parser($this->getTimeZoneProvider('CEST'));
- $this->assertEquals($dir, $parser->parseDir($output, ''));
- }
-}
diff --git a/apps/files_external/3rdparty/icewind/smb/tests/Server.php b/apps/files_external/3rdparty/icewind/smb/tests/Server.php
deleted file mode 100644
index 9f62886654f..00000000000
--- a/apps/files_external/3rdparty/icewind/smb/tests/Server.php
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-/**
- * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Licensed under the MIT license:
- * http://opensource.org/licenses/MIT
- */
-
-namespace Icewind\SMB\Test;
-
-class Server extends \PHPUnit_Framework_TestCase {
- /**
- * @var \Icewind\SMB\Server $server
- */
- private $server;
-
- private $config;
-
- public function setUp() {
- $this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
- $this->server = new \Icewind\SMB\Server($this->config->host, $this->config->user, $this->config->password);
- }
-
- public function testListShares() {
- $shares = $this->server->listShares();
- foreach ($shares as $share) {
- if ($share->getName() === $this->config->share) {
- return;
- }
- }
- $this->fail('Share "' . $this->config->share . '" not found');
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\AuthenticationException
- */
- public function testWrongUserName() {
- $this->markTestSkipped('This fails for no reason on travis');
- $server = new \Icewind\SMB\Server($this->config->host, uniqid(), uniqid());
- $server->listShares();
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\AuthenticationException
- */
- public function testWrongPassword() {
- $server = new \Icewind\SMB\Server($this->config->host, $this->config->user, uniqid());
- $server->listShares();
- }
-
- /**
- * @expectedException \Icewind\SMB\Exception\InvalidHostException
- */
- public function testWrongHost() {
- $server = new \Icewind\SMB\Server(uniqid(), $this->config->user, $this->config->password);
- $server->listShares();
- }
-}
diff --git a/apps/files_external/3rdparty/icewind/smb/tests/Share.php b/apps/files_external/3rdparty/icewind/smb/tests/Share.php
deleted file mode 100644
index a629914d748..00000000000
--- a/apps/files_external/3rdparty/icewind/smb/tests/Share.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-/**
- * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
- * This file is licensed under the Licensed under the MIT license:
- * http://opensource.org/licenses/MIT
- */
-
-namespace Icewind\SMB\Test;
-
-use Icewind\SMB\Server as NormalServer;
-
-class Share extends AbstractShare {
- public function setUp() {
- $this->config = json_decode(file_get_contents(__DIR__ . '/config.json'));
- $this->server = new NormalServer($this->config->host, $this->config->user, $this->config->password);
- $this->share = $this->server->getShare($this->config->share);
- if ($this->config->root) {
- $this->root = '/' . $this->config->root . '/' . uniqid();
- } else {
- $this->root = '/' . uniqid();
- }
- $this->share->mkdir($this->root);
- }
-}
diff --git a/apps/files_external/3rdparty/icewind/smb/tests/config.json b/apps/files_external/3rdparty/icewind/smb/tests/config.json
deleted file mode 100644
index 0ecd7e3715d..00000000000
--- a/apps/files_external/3rdparty/icewind/smb/tests/config.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "host": "localhost",
- "user": "test",
- "password": "test",
- "share": "test",
- "root": "test"
-}
diff --git a/apps/files_external/3rdparty/icewind/smb/tests/phpunit.xml b/apps/files_external/3rdparty/icewind/smb/tests/phpunit.xml
deleted file mode 100644
index 3ab244dd34f..00000000000
--- a/apps/files_external/3rdparty/icewind/smb/tests/phpunit.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<phpunit bootstrap="bootstrap.php">
- <testsuite name='SMB'>
- <directory suffix='.php'>./</directory>
- </testsuite>
-</phpunit>
diff --git a/apps/files_external/appinfo/app.php b/apps/files_external/appinfo/app.php
index 66897eba3d3..4bdfd316799 100644
--- a/apps/files_external/appinfo/app.php
+++ b/apps/files_external/appinfo/app.php
@@ -30,9 +30,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
-$app = new \OCA\Files_external\Appinfo\Application();
-
-$l = \OC::$server->getL10N('files_external');
OC::$CLASSPATH['OC\Files\Storage\StreamWrapper'] = 'files_external/lib/streamwrapper.php';
OC::$CLASSPATH['OC\Files\Storage\FTP'] = 'files_external/lib/ftp.php';
@@ -50,6 +47,12 @@ OC::$CLASSPATH['OCA\Files\External\Api'] = 'files_external/lib/api.php';
require_once __DIR__ . '/../3rdparty/autoload.php';
+// register Application object singleton
+\OC_Mount_Config::$app = new \OCA\Files_external\Appinfo\Application();
+$appContainer = \OC_Mount_Config::$app->getContainer();
+
+$l = \OC::$server->getL10N('files_external');
+
OCP\App::registerAdmin('files_external', 'settings');
if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == 'yes') {
OCP\App::registerPersonal('files_external', 'personal');
@@ -74,6 +77,10 @@ OC_Mount_Config::registerBackend('\OC\Files\Storage\Local', [
'datadir' => (string)$l->t('Location')
],
]);
+// Local must only be visible to the admin
+$appContainer->query('OCA\Files_External\Service\BackendService')
+ ->getBackend('\OC\Files\Storage\Local')
+ ->setAllowedVisibility(\OCA\Files_External\Service\BackendService::VISIBILITY_ADMIN);
OC_Mount_Config::registerBackend('\OC\Files\Storage\AmazonS3', [
'backend' => (string)$l->t('Amazon S3'),
@@ -237,5 +244,5 @@ OC_Mount_Config::registerBackend('\OC\Files\Storage\SFTP_Key', [
'custom' => 'sftp_key',
]
);
-$mountProvider = new \OCA\Files_External\Config\ConfigAdapter();
+$mountProvider = $appContainer->query('OCA\Files_External\Config\ConfigAdapter');
\OC::$server->getMountProviderCollection()->registerProvider($mountProvider);
diff --git a/apps/files_external/appinfo/application.php b/apps/files_external/appinfo/application.php
index d77a302466c..38b9e9b7c36 100644
--- a/apps/files_external/appinfo/application.php
+++ b/apps/files_external/appinfo/application.php
@@ -3,6 +3,7 @@
* @author Morris Jobke <hey@morrisjobke.de>
* @author Ross Nicoll <jrn@jrn.me.uk>
* @author Vincent Petry <pvince81@owncloud.com>
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
@@ -26,6 +27,9 @@ namespace OCA\Files_External\AppInfo;
use \OCA\Files_External\Controller\AjaxController;
use \OCP\AppFramework\App;
use \OCP\IContainer;
+use \OCA\Files_External\Service\BackendService;
+use \OCA\Files_External\Lib\BackendConfig;
+use \OCA\Files_External\Lib\BackendParameter;
/**
* @package OCA\Files_External\Appinfo
@@ -45,5 +49,33 @@ class Application extends App {
$c->query('Request')
);
});
+
+ $this->loadBackends();
+ $this->loadAuthMechanisms();
+ }
+
+ /**
+ * Load storage backends provided by this app
+ */
+ protected function loadBackends() {
+ $container = $this->getContainer();
+ $service = $container->query('OCA\\Files_External\\Service\\BackendService');
+ }
+
+ /**
+ * Load authentication mechanisms provided by this app
+ */
+ protected function loadAuthMechanisms() {
+ $container = $this->getContainer();
+ $service = $container->query('OCA\\Files_External\\Service\\BackendService');
+
+ $service->registerAuthMechanisms([
+ // AuthMechanism::SCHEME_NULL mechanism
+ $container->query('OCA\Files_External\Lib\Auth\NullMechanism'),
+
+ // AuthMechanism::SCHEME_BUILTIN mechanism
+ $container->query('OCA\Files_External\Lib\Auth\Builtin'),
+ ]);
}
+
}
diff --git a/apps/files_external/appinfo/routes.php b/apps/files_external/appinfo/routes.php
index bc4b0e98c91..213e7b28dc1 100644
--- a/apps/files_external/appinfo/routes.php
+++ b/apps/files_external/appinfo/routes.php
@@ -28,8 +28,7 @@ namespace OCA\Files_External\AppInfo;
/**
* @var $this \OC\Route\Router
**/
-$application = new Application();
-$application->registerRoutes(
+\OC_Mount_Config::$app->registerRoutes(
$this,
array(
'resources' => array(
diff --git a/apps/files_external/controller/globalstoragescontroller.php b/apps/files_external/controller/globalstoragescontroller.php
index 33f870d48e3..756a34fc5d4 100644
--- a/apps/files_external/controller/globalstoragescontroller.php
+++ b/apps/files_external/controller/globalstoragescontroller.php
@@ -63,7 +63,8 @@ class GlobalStoragesController extends StoragesController {
* Create an external storage entry.
*
* @param string $mountPoint storage mount point
- * @param string $backendClass backend class name
+ * @param string $backend backend identifier
+ * @param string $authMechanism authentication mechanism identifier
* @param array $backendOptions backend-specific options
* @param array $mountOptions mount-specific options
* @param array $applicableUsers users for which to mount the storage
@@ -74,21 +75,27 @@ class GlobalStoragesController extends StoragesController {
*/
public function create(
$mountPoint,
- $backendClass,
+ $backend,
+ $authMechanism,
$backendOptions,
$mountOptions,
$applicableUsers,
$applicableGroups,
$priority
) {
- $newStorage = new StorageConfig();
- $newStorage->setMountPoint($mountPoint);
- $newStorage->setBackendClass($backendClass);
- $newStorage->setBackendOptions($backendOptions);
- $newStorage->setMountOptions($mountOptions);
- $newStorage->setApplicableUsers($applicableUsers);
- $newStorage->setApplicableGroups($applicableGroups);
- $newStorage->setPriority($priority);
+ $newStorage = $this->createStorage(
+ $mountPoint,
+ $backend,
+ $authMechanism,
+ $backendOptions,
+ $mountOptions,
+ $applicableUsers,
+ $applicableGroups,
+ $priority
+ );
+ if ($newStorage instanceof DataResponse) {
+ return $newStorage;
+ }
$response = $this->validate($newStorage);
if (!empty($response)) {
@@ -110,7 +117,8 @@ class GlobalStoragesController extends StoragesController {
*
* @param int $id storage id
* @param string $mountPoint storage mount point
- * @param string $backendClass backend class name
+ * @param string $backend backend identifier
+ * @param string $authMechanism authentication mechansim identifier
* @param array $backendOptions backend-specific options
* @param array $mountOptions mount-specific options
* @param array $applicableUsers users for which to mount the storage
@@ -122,21 +130,28 @@ class GlobalStoragesController extends StoragesController {
public function update(
$id,
$mountPoint,
- $backendClass,
+ $backend,
+ $authMechanism,
$backendOptions,
$mountOptions,
$applicableUsers,
$applicableGroups,
$priority
) {
- $storage = new StorageConfig($id);
- $storage->setMountPoint($mountPoint);
- $storage->setBackendClass($backendClass);
- $storage->setBackendOptions($backendOptions);
- $storage->setMountOptions($mountOptions);
- $storage->setApplicableUsers($applicableUsers);
- $storage->setApplicableGroups($applicableGroups);
- $storage->setPriority($priority);
+ $storage = $this->createStorage(
+ $mountPoint,
+ $backend,
+ $authMechanism,
+ $backendOptions,
+ $mountOptions,
+ $applicableUsers,
+ $applicableGroups,
+ $priority
+ );
+ if ($storage instanceof DataResponse) {
+ return $storage;
+ }
+ $storage->setId($id);
$response = $this->validate($storage);
if (!empty($response)) {
diff --git a/apps/files_external/controller/storagescontroller.php b/apps/files_external/controller/storagescontroller.php
index c09ceacc7d7..3d91af8bd8f 100644
--- a/apps/files_external/controller/storagescontroller.php
+++ b/apps/files_external/controller/storagescontroller.php
@@ -32,6 +32,10 @@ use \OCP\AppFramework\Http;
use \OCA\Files_external\Service\StoragesService;
use \OCA\Files_external\NotFoundException;
use \OCA\Files_external\Lib\StorageConfig;
+use \OCA\Files_External\Lib\Backend\Backend;
+use \OCA\Files_External\Lib\Auth\AuthMechanism;
+use \OCP\Files\StorageNotAvailableException;
+use \OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException;
/**
* Base class for storages controllers
@@ -72,6 +76,51 @@ abstract class StoragesController extends Controller {
}
/**
+ * Create a storage from its parameters
+ *
+ * @param string $mountPoint storage mount point
+ * @param string $backend backend identifier
+ * @param string $authMechanism authentication mechanism identifier
+ * @param array $backendOptions backend-specific options
+ * @param array|null $mountOptions mount-specific options
+ * @param array|null $applicableUsers users for which to mount the storage
+ * @param array|null $applicableGroups groups for which to mount the storage
+ * @param int|null $priority priority
+ *
+ * @return StorageConfig|DataResponse
+ */
+ protected function createStorage(
+ $mountPoint,
+ $backend,
+ $authMechanism,
+ $backendOptions,
+ $mountOptions = null,
+ $applicableUsers = null,
+ $applicableGroups = null,
+ $priority = null
+ ) {
+ try {
+ return $this->service->createStorage(
+ $mountPoint,
+ $backend,
+ $authMechanism,
+ $backendOptions,
+ $mountOptions,
+ $applicableUsers,
+ $applicableGroups,
+ $priority
+ );
+ } catch (\InvalidArgumentException $e) {
+ return new DataResponse(
+ [
+ 'message' => (string)$this->l10n->t('Invalid backend or authentication mechanism class')
+ ],
+ Http::STATUS_UNPROCESSABLE_ENTITY
+ );
+ }
+ }
+
+ /**
* Validate storage config
*
* @param StorageConfig $storage storage config
@@ -89,18 +138,39 @@ abstract class StoragesController extends Controller {
);
}
- // TODO: validate that other attrs are set
-
- $backends = \OC_Mount_Config::getBackends();
- if (!isset($backends[$storage->getBackendClass()])) {
+ /** @var Backend */
+ $backend = $storage->getBackend();
+ /** @var AuthMechanism */
+ $authMechanism = $storage->getAuthMechanism();
+ if (!$backend || $backend->checkDependencies()) {
// invalid backend
return new DataResponse(
array(
- 'message' => (string)$this->l10n->t('Invalid storage backend "%s"', array($storage->getBackendClass()))
+ 'message' => (string)$this->l10n->t('Invalid storage backend "%s"', [
+ $storage->getBackend()->getIdentifier()
+ ])
),
Http::STATUS_UNPROCESSABLE_ENTITY
);
}
+ if (!$backend->validateStorage($storage)) {
+ // unsatisfied parameters
+ return new DataResponse(
+ array(
+ 'message' => (string)$this->l10n->t('Unsatisfied backend parameters')
+ ),
+ Http::STATUS_UNPROCESSABLE_ENTITY
+ );
+ }
+ if (!$authMechanism->validateStorage($storage)) {
+ // unsatisfied parameters
+ return new DataResponse(
+ [
+ 'message' => (string)$this->l10n->t('Unsatisfied authentication mechanism parameters')
+ ],
+ Http::STATUS_UNPROCESSABLE_ENTITY
+ );
+ }
return null;
}
@@ -114,14 +184,27 @@ abstract class StoragesController extends Controller {
* @param StorageConfig $storage storage configuration
*/
protected function updateStorageStatus(StorageConfig &$storage) {
- // update status (can be time-consuming)
- $storage->setStatus(
- \OC_Mount_Config::getBackendStatus(
- $storage->getBackendClass(),
- $storage->getBackendOptions(),
- false
- )
- );
+ try {
+ /** @var AuthMechanism */
+ $authMechanism = $storage->getAuthMechanism();
+ $authMechanism->manipulateStorageConfig($storage);
+ /** @var Backend */
+ $backend = $storage->getBackend();
+ $backend->manipulateStorageConfig($storage);
+
+ // update status (can be time-consuming)
+ $storage->setStatus(
+ \OC_Mount_Config::getBackendStatus(
+ $backend->getStorageClass(),
+ $storage->getBackendOptions(),
+ false
+ )
+ );
+ } catch (InsufficientDataForMeaningfulAnswerException $e) {
+ $storage->setStatus(\OC_Mount_Config::STATUS_INDETERMINATE);
+ } catch (StorageNotAvailableException $e) {
+ $storage->setStatus(\OC_Mount_Config::STATUS_ERROR);
+ }
}
/**
diff --git a/apps/files_external/controller/userstoragescontroller.php b/apps/files_external/controller/userstoragescontroller.php
index f5d22e5caa6..0d41e088a76 100644
--- a/apps/files_external/controller/userstoragescontroller.php
+++ b/apps/files_external/controller/userstoragescontroller.php
@@ -30,8 +30,10 @@ use \OCP\AppFramework\Http\DataResponse;
use \OCP\AppFramework\Controller;
use \OCP\AppFramework\Http;
use \OCA\Files_external\Service\UserStoragesService;
+use \OCA\Files_External\Service\BackendService;
use \OCA\Files_external\NotFoundException;
use \OCA\Files_external\Lib\StorageConfig;
+use \OCA\Files_External\Lib\Backend\Backend;
/**
* User storages controller
@@ -69,17 +71,20 @@ class UserStoragesController extends StoragesController {
protected function validate(StorageConfig $storage) {
$result = parent::validate($storage);
- if ($result != null) {
+ if ($result !== null) {
return $result;
}
// Verify that the mount point applies for the current user
// Prevent non-admin users from mounting local storage and other disabled backends
- $allowedBackends = \OC_Mount_Config::getPersonalBackends();
- if (!isset($allowedBackends[$storage->getBackendClass()])) {
+ /** @var Backend */
+ $backend = $storage->getBackend();
+ if (!$backend->isVisibleFor(BackendService::VISIBILITY_PERSONAL)) {
return new DataResponse(
array(
- 'message' => (string)$this->l10n->t('Invalid storage backend "%s"', array($storage->getBackendClass()))
+ 'message' => (string)$this->l10n->t('Admin-only storage backend "%s"', [
+ $storage->getBackend()->getIdentifier()
+ ])
),
Http::STATUS_UNPROCESSABLE_ENTITY
);
@@ -103,7 +108,8 @@ class UserStoragesController extends StoragesController {
* Create an external storage entry.
*
* @param string $mountPoint storage mount point
- * @param string $backendClass backend class name
+ * @param string $backend backend identifier
+ * @param string $authMechanism authentication mechanism identifier
* @param array $backendOptions backend-specific options
* @param array $mountOptions backend-specific mount options
*
@@ -113,15 +119,21 @@ class UserStoragesController extends StoragesController {
*/
public function create(
$mountPoint,
- $backendClass,
+ $backend,
+ $authMechanism,
$backendOptions,
$mountOptions
) {
- $newStorage = new StorageConfig();
- $newStorage->setMountPoint($mountPoint);
- $newStorage->setBackendClass($backendClass);
- $newStorage->setBackendOptions($backendOptions);
- $newStorage->setMountOptions($mountOptions);
+ $newStorage = $this->createStorage(
+ $mountPoint,
+ $backend,
+ $authMechanism,
+ $backendOptions,
+ $mountOptions
+ );
+ if ($newStorage instanceOf DataResponse) {
+ return $newStorage;
+ }
$response = $this->validate($newStorage);
if (!empty($response)) {
@@ -142,7 +154,8 @@ class UserStoragesController extends StoragesController {
*
* @param int $id storage id
* @param string $mountPoint storage mount point
- * @param string $backendClass backend class name
+ * @param string $backend backend identifier
+ * @param string $authMechanism authentication mechanism identifier
* @param array $backendOptions backend-specific options
* @param array $mountOptions backend-specific mount options
*
@@ -153,15 +166,22 @@ class UserStoragesController extends StoragesController {
public function update(
$id,
$mountPoint,
- $backendClass,
+ $backend,
+ $authMechanism,
$backendOptions,
$mountOptions
) {
- $storage = new StorageConfig($id);
- $storage->setMountPoint($mountPoint);
- $storage->setBackendClass($backendClass);
- $storage->setBackendOptions($backendOptions);
- $storage->setMountOptions($mountOptions);
+ $storage = $this->createStorage(
+ $mountPoint,
+ $backend,
+ $authMechanism,
+ $backendOptions,
+ $mountOptions
+ );
+ if ($storage instanceOf DataResponse) {
+ return $storage;
+ }
+ $storage->setId($id);
$response = $this->validate($storage);
if (!empty($response)) {
diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js
index 287b4664541..6bf0143f1c0 100644
--- a/apps/files_external/js/settings.js
+++ b/apps/files_external/js/settings.js
@@ -191,7 +191,8 @@ var StorageConfig = function(id) {
StorageConfig.Status = {
IN_PROGRESS: -1,
SUCCESS: 0,
- ERROR: 1
+ ERROR: 1,
+ INDETERMINATE: 2
};
/**
* @memberof OCA.External.Settings
@@ -214,11 +215,18 @@ StorageConfig.prototype = {
mountPoint: '',
/**
- * Backend class name
+ * Backend
*
* @type string
*/
- backendClass: null,
+ backend: null,
+
+ /**
+ * Authentication mechanism
+ *
+ * @type string
+ */
+ authMechanism: null,
/**
* Backend-specific configuration
@@ -272,7 +280,8 @@ StorageConfig.prototype = {
getData: function() {
var data = {
mountPoint: this.mountPoint,
- backendClass: this.backendClass,
+ backend: this.backend,
+ authMechanism: this.authMechanism,
backendOptions: this.backendOptions
};
if (this.id) {
@@ -579,6 +588,13 @@ MountConfigListView.prototype = {
*/
_allBackends: null,
+ /**
+ * List of all supported authentication mechanisms
+ *
+ * @type Object.<string,Object>
+ */
+ _allAuthMechanisms: null,
+
_encryptionEnabled: false,
/**
@@ -605,6 +621,7 @@ MountConfigListView.prototype = {
// read the backend config that was carefully crammed
// into the data-configurations attribute of the select
this._allBackends = this.$el.find('.selectBackend').data('configurations');
+ this._allAuthMechanisms = this.$el.find('#addMountPoint .authentication').data('mechanisms');
//initialize hidden input field with list of users and groups
this.$el.find('tr:not(#addMountPoint)').each(function(i,tr) {
@@ -660,6 +677,7 @@ MountConfigListView.prototype = {
});
this.$el.on('change', '.selectBackend', _.bind(this._onSelectBackend, this));
+ this.$el.on('change', '.selectAuthMechanism', _.bind(this._onSelectAuthMechanism, this));
},
_onChange: function(event) {
@@ -687,47 +705,34 @@ MountConfigListView.prototype = {
$el.find('tbody').append($tr.clone());
$el.find('tbody tr').last().find('.mountPoint input').val('');
var selected = $target.find('option:selected').text();
- var backendClass = $target.val();
+ var backend = $target.val();
$tr.find('.backend').text(selected);
if ($tr.find('.mountPoint input').val() === '') {
$tr.find('.mountPoint input').val(this._suggestMountPoint(selected));
}
- $tr.addClass(backendClass);
- $tr.find('.backend').data('class', backendClass);
- var configurations = this._allBackends;
- var $td = $tr.find('td.configuration');
- $.each(configurations, function(backend, parameters) {
- if (backend === backendClass) {
- $.each(parameters['configuration'], function(parameter, placeholder) {
- var is_optional = false;
- if (placeholder.indexOf('&') === 0) {
- is_optional = true;
- placeholder = placeholder.substring(1);
- }
- var newElement;
- if (placeholder.indexOf('*') === 0) {
- var class_string = is_optional ? ' optional' : '';
- newElement = $('<input type="password" class="added' + class_string + '" data-parameter="'+parameter+'" placeholder="'+placeholder.substring(1)+'" />');
- } else if (placeholder.indexOf('!') === 0) {
- newElement = $('<label><input type="checkbox" class="added" data-parameter="'+parameter+'" />'+placeholder.substring(1)+'</label>');
- } else if (placeholder.indexOf('#') === 0) {
- newElement = $('<input type="hidden" class="added" data-parameter="'+parameter+'" />');
- } else {
- var class_string = is_optional ? ' optional' : '';
- newElement = $('<input type="text" class="added' + class_string + '" data-parameter="'+parameter+'" placeholder="'+placeholder+'" />');
- }
- highlightInput(newElement);
- $td.append(newElement);
- });
- var priorityEl = $('<input type="hidden" class="priority" value="' + parameters['priority'] + '" />');
- $tr.append(priorityEl);
- if (parameters['custom'] && $el.find('tbody tr.'+backendClass.replace(/\\/g, '\\\\')).length === 1) {
- OC.addScript('files_external', parameters['custom']);
- }
- $td.children().not('[type=hidden]').first().focus();
- return false;
+ $tr.addClass(backend);
+ $tr.find('.backend').data('class', backend);
+ var backendConfiguration = this._allBackends[backend];
+
+ var selectAuthMechanism = $('<select class="selectAuthMechanism"></select>');
+ $.each(this._allAuthMechanisms, function(authClass, authMechanism) {
+ if (backendConfiguration['authSchemes'][authMechanism['scheme']]) {
+ selectAuthMechanism.append(
+ $('<option value="'+authClass+'" data-scheme="'+authMechanism['scheme']+'">'+authMechanism['name']+'</option>')
+ );
}
});
+ $tr.find('td.authentication').append(selectAuthMechanism);
+
+ var $td = $tr.find('td.configuration');
+ $.each(backendConfiguration['configuration'], _.partial(this.writeParameterInput, $td));
+
+ selectAuthMechanism.trigger('change'); // generate configuration parameters for auth mechanism
+
+ var priorityEl = $('<input type="hidden" class="priority" value="' + backendConfiguration['priority'] + '" />');
+ $tr.append(priorityEl);
+ $td.children().not('[type=hidden]').first().focus();
+
$tr.find('td').last().attr('class', 'remove');
$tr.find('td.mountOptionsToggle').removeClass('hidden');
$tr.find('td').last().removeAttr('style');
@@ -736,6 +741,41 @@ MountConfigListView.prototype = {
addSelect2($tr.find('.applicableUsers'), this._userListLimit);
},
+ _onSelectAuthMechanism: function(event) {
+ var $target = $(event.target);
+ var $tr = $target.closest('tr');
+
+ var authMechanism = $target.val();
+ var authMechanismConfiguration = this._allAuthMechanisms[authMechanism];
+ var $td = $tr.find('td.configuration');
+ $td.find('.auth-param').remove();
+
+ $.each(authMechanismConfiguration['configuration'], _.partial(
+ this.writeParameterInput, $td, _, _, ['auth-param']
+ ));
+ },
+
+ writeParameterInput: function($td, parameter, placeholder, classes) {
+ classes = $.isArray(classes) ? classes : [];
+ classes.push('added');
+ if (placeholder.indexOf('&') === 0) {
+ classes.push('optional');
+ placeholder = placeholder.substring(1);
+ }
+ var newElement;
+ if (placeholder.indexOf('*') === 0) {
+ newElement = $('<input type="password" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" placeholder="'+placeholder.substring(1)+'" />');
+ } else if (placeholder.indexOf('!') === 0) {
+ newElement = $('<label><input type="checkbox" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" />'+placeholder.substring(1)+'</label>');
+ } else if (placeholder.indexOf('#') === 0) {
+ newElement = $('<input type="hidden" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" />');
+ } else {
+ newElement = $('<input type="text" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" placeholder="'+placeholder+'" />');
+ }
+ highlightInput(newElement);
+ $td.append(newElement);
+ },
+
/**
* Gets the storage model from the given row
*
@@ -750,7 +790,8 @@ MountConfigListView.prototype = {
}
var storage = new this._storageConfigClass(storageId);
storage.mountPoint = $tr.find('.mountPoint input').val();
- storage.backendClass = $tr.find('.backend').data('class');
+ storage.backend = $tr.find('.backend').data('class');
+ storage.authMechanism = $tr.find('.selectAuthMechanism').val();
var classOptions = {};
var configuration = $tr.find('.configuration input');
@@ -903,7 +944,7 @@ MountConfigListView.prototype = {
*/
updateStatus: function($tr, status) {
var $statusSpan = $tr.find('.status span');
- $statusSpan.removeClass('success error loading-small');
+ $statusSpan.removeClass('loading-small success indeterminate error');
switch (status) {
case StorageConfig.Status.IN_PROGRESS:
$statusSpan.addClass('loading-small');
@@ -911,6 +952,9 @@ MountConfigListView.prototype = {
case StorageConfig.Status.SUCCESS:
$statusSpan.addClass('success');
break;
+ case StorageConfig.Status.INDETERMINATE:
+ $statusSpan.addClass('indeterminate');
+ break;
default:
$statusSpan.addClass('error');
}
diff --git a/apps/files_external/lib/auth/authmechanism.php b/apps/files_external/lib/auth/authmechanism.php
new file mode 100644
index 00000000000..11d99bb330d
--- /dev/null
+++ b/apps/files_external/lib/auth/authmechanism.php
@@ -0,0 +1,116 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib\Auth;
+
+use \OCA\Files_External\Lib\StorageConfig;
+use \OCA\Files_External\Lib\VisibilityTrait;
+use \OCA\Files_External\Lib\IdentifierTrait;
+use \OCA\Files_External\Lib\FrontendDefinitionTrait;
+use \OCA\Files_External\Lib\StorageModifierTrait;
+
+/**
+ * Authentication mechanism
+ *
+ * An authentication mechanism can have services injected during construction,
+ * such as \OCP\IDB for database operations. This allows an authentication
+ * mechanism to perform advanced operations based on provided information.
+ *
+ * An authenication scheme defines the parameter interface, common to the
+ * storage implementation, the backend and the authentication mechanism.
+ * A storage implementation expects parameters according to the authentication
+ * scheme, which are provided from the authentication mechanism.
+ *
+ * This class uses the following traits:
+ * - VisibilityTrait
+ * Restrict usage to admin-only/none
+ * - FrontendDefinitionTrait
+ * Specify configuration parameters and other definitions
+ * - StorageModifierTrait
+ * Object can affect storage mounting
+ */
+class AuthMechanism implements \JsonSerializable {
+
+ /** Standard authentication schemes */
+ const SCHEME_NULL = 'null';
+ const SCHEME_BUILTIN = 'builtin';
+ const SCHEME_PASSWORD = 'password';
+ const SCHEME_OAUTH1 = 'oauth1';
+ const SCHEME_OAUTH2 = 'oauth2';
+ const SCHEME_PUBLICKEY = 'publickey';
+ const SCHEME_OPENSTACK = 'openstack';
+
+ use VisibilityTrait;
+ use FrontendDefinitionTrait;
+ use StorageModifierTrait;
+ use IdentifierTrait;
+
+ /** @var string */
+ protected $scheme;
+
+ /**
+ * Get the authentication scheme implemented
+ * See self::SCHEME_* constants
+ *
+ * @return string
+ */
+ public function getScheme() {
+ return $this->scheme;
+ }
+
+ /**
+ * @param string $scheme
+ * @return self
+ */
+ public function setScheme($scheme) {
+ $this->scheme = $scheme;
+ return $this;
+ }
+
+ /**
+ * Serialize into JSON for client-side JS
+ *
+ * @return array
+ */
+ public function jsonSerialize() {
+ $data = $this->jsonSerializeDefinition();
+ $data['scheme'] = $this->getScheme();
+
+ return $data;
+ }
+
+ /**
+ * Check if parameters are satisfied in a StorageConfig
+ *
+ * @param StorageConfig $storage
+ * @return bool
+ */
+ public function validateStorage(StorageConfig $storage) {
+ // does the backend actually support this scheme
+ $supportedSchemes = $storage->getBackend()->getAuthSchemes();
+ if (!isset($supportedSchemes[$this->getScheme()])) {
+ return false;
+ }
+
+ return $this->validateStorageDefinition($storage);
+ }
+
+}
diff --git a/apps/files_external/lib/auth/builtin.php b/apps/files_external/lib/auth/builtin.php
new file mode 100644
index 00000000000..ee28a4e8a5c
--- /dev/null
+++ b/apps/files_external/lib/auth/builtin.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib\Auth;
+
+use \OCP\IL10N;
+use \OCA\Files_External\Lib\Auth\AuthMechanism;
+use \OCA\Files_external\Lib\StorageConfig;
+
+/**
+ * Builtin authentication mechanism, for legacy backends
+ */
+class Builtin extends AuthMechanism {
+
+ public function __construct(IL10N $l) {
+ $this
+ ->setIdentifier('builtin::builtin')
+ ->setScheme(self::SCHEME_BUILTIN)
+ ->setText($l->t('Builtin'))
+ ;
+ }
+
+}
diff --git a/apps/files_external/lib/auth/nullmechanism.php b/apps/files_external/lib/auth/nullmechanism.php
new file mode 100644
index 00000000000..1765fc67396
--- /dev/null
+++ b/apps/files_external/lib/auth/nullmechanism.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib\Auth;
+
+use \OCP\IL10N;
+use \OCA\Files_External\Lib\Auth\AuthMechanism;
+use \OCA\Files_external\Lib\StorageConfig;
+
+/**
+ * Null authentication mechanism
+ */
+class NullMechanism extends AuthMechanism {
+
+ public function __construct(IL10N $l) {
+ $this
+ ->setIdentifier('null::null')
+ ->setScheme(self::SCHEME_NULL)
+ ->setText($l->t('None'))
+ ;
+ }
+
+}
diff --git a/apps/files_external/lib/backend/backend.php b/apps/files_external/lib/backend/backend.php
new file mode 100644
index 00000000000..90d5d38ed94
--- /dev/null
+++ b/apps/files_external/lib/backend/backend.php
@@ -0,0 +1,164 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib\Backend;
+
+use \OCA\Files_External\Lib\StorageConfig;
+use \OCA\Files_External\Lib\VisibilityTrait;
+use \OCA\Files_External\Lib\FrontendDefinitionTrait;
+use \OCA\Files_External\Lib\PriorityTrait;
+use \OCA\Files_External\Lib\DependencyTrait;
+use \OCA\Files_External\Lib\StorageModifierTrait;
+use \OCA\Files_External\Lib\IdentifierTrait;
+use \OCA\Files_External\Lib\Auth\AuthMechanism;
+
+/**
+ * Storage backend
+ *
+ * A backend can have services injected during construction,
+ * such as \OCP\IDB for database operations. This allows a backend
+ * to perform advanced operations based on provided information.
+ *
+ * An authenication scheme defines the parameter interface, common to the
+ * storage implementation, the backend and the authentication mechanism.
+ * A storage implementation expects parameters according to the authentication
+ * scheme, which are provided from the authentication mechanism.
+ *
+ * This class uses the following traits:
+ * - VisibilityTrait
+ * Restrict usage to admin-only/none
+ * - FrontendDefinitionTrait
+ * Specify configuration parameters and other definitions
+ * - PriorityTrait
+ * Allow objects to prioritize over others with the same mountpoint
+ * - DependencyTrait
+ * The object requires certain dependencies to be met
+ * - StorageModifierTrait
+ * Object can affect storage mounting
+ */
+class Backend implements \JsonSerializable {
+
+ use VisibilityTrait;
+ use FrontendDefinitionTrait;
+ use PriorityTrait;
+ use DependencyTrait;
+ use StorageModifierTrait;
+ use IdentifierTrait;
+
+ /** @var string storage class */
+ private $storageClass;
+
+ /** @var array 'scheme' => true, supported authentication schemes */
+ private $authSchemes = [];
+
+ /** @var AuthMechanism|callable authentication mechanism fallback */
+ private $legacyAuthMechanism;
+
+ /**
+ * @return string
+ */
+ public function getStorageClass() {
+ return $this->storageClass;
+ }
+
+ /**
+ * @param string $class
+ * @return self
+ */
+ public function setStorageClass($class) {
+ $this->storageClass = $class;
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAuthSchemes() {
+ if (empty($this->authSchemes)) {
+ return [AuthMechanism::SCHEME_NULL => true];
+ }
+ return $this->authSchemes;
+ }
+
+ /**
+ * @param string $scheme
+ * @return self
+ */
+ public function addAuthScheme($scheme) {
+ $this->authSchemes[$scheme] = true;
+ return $this;
+ }
+
+ /**
+ * @param array $parameters storage parameters, for dynamic mechanism selection
+ * @return AuthMechanism
+ */
+ public function getLegacyAuthMechanism(array $parameters = []) {
+ if (is_callable($this->legacyAuthMechanism)) {
+ return call_user_func($this->legacyAuthMechanism, $parameters);
+ }
+ return $this->legacyAuthMechanism;
+ }
+
+ /**
+ * @param AuthMechanism $authMechanism
+ * @return self
+ */
+ public function setLegacyAuthMechanism(AuthMechanism $authMechanism) {
+ $this->legacyAuthMechanism = $authMechanism;
+ return $this;
+ }
+
+ /**
+ * @param callable $callback dynamic auth mechanism selection
+ * @return self
+ */
+ public function setLegacyAuthMechanismCallback(callable $callback) {
+ $this->legacyAuthMechanism = $callback;
+ }
+
+ /**
+ * Serialize into JSON for client-side JS
+ *
+ * @return array
+ */
+ public function jsonSerialize() {
+ $data = $this->jsonSerializeDefinition();
+
+ $data['backend'] = $data['name']; // legacy compat
+ $data['priority'] = $this->getPriority();
+ $data['authSchemes'] = $this->getAuthSchemes();
+
+ return $data;
+ }
+
+ /**
+ * Check if parameters are satisfied in a StorageConfig
+ *
+ * @param StorageConfig $storage
+ * @return bool
+ */
+ public function validateStorage(StorageConfig $storage) {
+ return $this->validateStorageDefinition($storage);
+ }
+
+}
+
diff --git a/apps/files_external/lib/backend/legacybackend.php b/apps/files_external/lib/backend/legacybackend.php
new file mode 100644
index 00000000000..0f60c2caa47
--- /dev/null
+++ b/apps/files_external/lib/backend/legacybackend.php
@@ -0,0 +1,85 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib\Backend;
+
+use \OCA\Files_External\Lib\DefinitionParameter;
+use \OCA\Files_External\Lib\Backend\Backend;
+use \OCA\Files_External\Lib\Auth\Builtin;
+
+/**
+ * Legacy compatibility for OC_Mount_Config::registerBackend()
+ */
+class LegacyBackend extends Backend {
+
+ /**
+ * @param string $class
+ * @param array $definition
+ * @param Builtin $authMechanism
+ */
+ public function __construct($class, array $definition, Builtin $authMechanism) {
+ $this
+ ->setIdentifier($class)
+ ->setStorageClass($class)
+ ->setText($definition['backend'])
+ ->addAuthScheme(Builtin::SCHEME_BUILTIN)
+ ->setLegacyAuthMechanism($authMechanism)
+ ;
+
+ foreach ($definition['configuration'] as $name => $placeholder) {
+ $flags = DefinitionParameter::FLAG_NONE;
+ $type = DefinitionParameter::VALUE_TEXT;
+ if ($placeholder[0] === '&') {
+ $flags = DefinitionParameter::FLAG_OPTIONAL;
+ $placeholder = substr($placeholder, 1);
+ }
+ switch ($placeholder[0]) {
+ case '!':
+ $type = DefinitionParameter::VALUE_BOOLEAN;
+ $placeholder = substr($placeholder, 1);
+ break;
+ case '*':
+ $type = DefinitionParameter::VALUE_PASSWORD;
+ $placeholder = substr($placeholder, 1);
+ break;
+ case '#':
+ $type = DefinitionParameter::VALUE_HIDDEN;
+ $placeholder = substr($placeholder, 1);
+ break;
+ }
+ $this->addParameter((new DefinitionParameter($name, $placeholder))
+ ->setType($type)
+ ->setFlags($flags)
+ );
+ }
+
+ if (isset($definition['priority'])) {
+ $this->setPriority($definition['priority']);
+ }
+ if (isset($definition['custom'])) {
+ $this->setCustomJs($definition['custom']);
+ }
+ if (isset($definition['has_dependencies']) && $definition['has_dependencies']) {
+ $this->setDependencyCheck($class . '::checkDependencies');
+ }
+ }
+
+}
diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php
index 8fcf39cc767..91c33ef10a5 100644
--- a/apps/files_external/lib/config.php
+++ b/apps/files_external/lib/config.php
@@ -32,6 +32,11 @@
*/
use phpseclib\Crypt\AES;
+use \OCA\Files_External\Appinfo\Application;
+use \OCA\Files_External\Lib\BackendConfig;
+use \OCA\Files_External\Service\BackendService;
+use \OCA\Files_External\Lib\Backend\LegacyBackend;
+use \OCA\Files_External\Lib\StorageConfig;
/**
* Class to configure mount.json globally and for users
@@ -47,75 +52,30 @@ class OC_Mount_Config {
// getBackendStatus return types
const STATUS_SUCCESS = 0;
const STATUS_ERROR = 1;
+ const STATUS_INDETERMINATE = 2;
// whether to skip backend test (for unit tests, as this static class is not mockable)
public static $skipTest = false;
- private static $backends = array();
+ /** @var Application */
+ public static $app;
/**
* @param string $class
* @param array $definition
* @return bool
+ * @deprecated 8.2.0 use \OCA\Files_External\Service\BackendService::registerBackend()
*/
public static function registerBackend($class, $definition) {
- if (!isset($definition['backend'])) {
- return false;
- }
-
- OC_Mount_Config::$backends[$class] = $definition;
- return true;
- }
-
- /**
- * Setup backends
- *
- * @return array of previously registered backends
- */
- public static function setUp($backends = array()) {
- $backup = self::$backends;
- self::$backends = $backends;
-
- return $backup;
- }
-
- /**
- * Get details on each of the external storage backends, used for the mount config UI
- * If a custom UI is needed, add the key 'custom' and a javascript file with that name will be loaded
- * If the configuration parameter should be secret, add a '*' to the beginning of the value
- * If the configuration parameter is a boolean, add a '!' to the beginning of the value
- * If the configuration parameter is optional, add a '&' to the beginning of the value
- * If the configuration parameter is hidden, add a '#' to the beginning of the value
- *
- * @return array
- */
- public static function getBackends() {
- $sortFunc = function ($a, $b) {
- return strcasecmp($a['backend'], $b['backend']);
- };
-
- $backEnds = array();
-
- foreach (OC_Mount_Config::$backends as $class => $backend) {
- if (isset($backend['has_dependencies']) and $backend['has_dependencies'] === true) {
- if (!method_exists($class, 'checkDependencies')) {
- \OCP\Util::writeLog('files_external',
- "Backend class $class has dependencies but doesn't provide method checkDependencies()",
- \OCP\Util::DEBUG);
- continue;
- } elseif ($class::checkDependencies() !== true) {
- continue;
- }
- }
- $backEnds[$class] = $backend;
- }
+ $backendService = self::$app->getContainer()->query('OCA\Files_External\Service\BackendService');
+ $auth = self::$app->getContainer()->query('OCA\Files_External\Lib\Auth\Builtin');
- uasort($backEnds, $sortFunc);
+ $backendService->registerBackend(new LegacyBackend($class, $definition, $auth));
- return $backEnds;
+ return true;
}
- /**
+ /*
* Hook that mounts the given user's visible mount points
*
* @param array $data
@@ -152,331 +112,124 @@ class OC_Mount_Config {
* Returns the mount points for the given user.
* The mount point is relative to the data directory.
*
- * @param string $user user
+ * @param string $uid user
* @return array of mount point string as key, mountpoint config as value
+ *
+ * @deprecated 8.2.0 use UserGlobalStoragesService::getAllStorages() and UserStoragesService::getAllStorages()
*/
- public static function getAbsoluteMountPoints($user) {
+ public static function getAbsoluteMountPoints($uid) {
$mountPoints = array();
- $backends = self::getBackends();
-
- // Load system mount points
- $mountConfig = self::readData();
+ $userGlobalStoragesService = self::$app->getContainer()->query('OCA\Files_External\Service\UserGlobalStoragesService');
+ $userStoragesService = self::$app->getContainer()->query('OCA\Files_External\Service\UserStoragesService');
+ $user = self::$app->getContainer()->query('OCP\IUserManager')->get($uid);
- // Global mount points (is this redundant?)
- if (isset($mountConfig[self::MOUNT_TYPE_GLOBAL])) {
- foreach ($mountConfig[self::MOUNT_TYPE_GLOBAL] as $mountPoint => $options) {
- $options['personal'] = false;
- $options['options'] = self::decryptPasswords($options['options']);
- if (!isset($options['priority'])) {
- $options['priority'] = $backends[$options['class']]['priority'];
- }
+ $userGlobalStoragesService->setUser($user);
+ $userStoragesService->setUser($user);
- // Override if priority greater
- if ((!isset($mountPoints[$mountPoint]))
- || ($options['priority'] >= $mountPoints[$mountPoint]['priority'])
- ) {
- $options['priority_type'] = self::MOUNT_TYPE_GLOBAL;
- $options['backend'] = $backends[$options['class']]['backend'];
- $mountPoints[$mountPoint] = $options;
- }
+ foreach ($userGlobalStoragesService->getAllStorages() as $storage) {
+ $mountPoint = '/'.$uid.'/files'.$storage->getMountPoint();
+ $mountEntry = self::prepareMountPointEntry($storage, false);
+ foreach ($mountEntry['options'] as &$option) {
+ $option = self::setUserVars($uid, $option);
}
+ $mountPoints[$mountPoint] = $mountEntry;
}
- // All user mount points
- if (isset($mountConfig[self::MOUNT_TYPE_USER]) && isset($mountConfig[self::MOUNT_TYPE_USER]['all'])) {
- $mounts = $mountConfig[self::MOUNT_TYPE_USER]['all'];
- foreach ($mounts as $mountPoint => $options) {
- $mountPoint = self::setUserVars($user, $mountPoint);
- foreach ($options as &$option) {
- $option = self::setUserVars($user, $option);
- }
- $options['personal'] = false;
- $options['options'] = self::decryptPasswords($options['options']);
- if (!isset($options['priority'])) {
- $options['priority'] = $backends[$options['class']]['priority'];
- }
- // Override if priority greater
- if ((!isset($mountPoints[$mountPoint]))
- || ($options['priority'] >= $mountPoints[$mountPoint]['priority'])
- ) {
- $options['priority_type'] = self::MOUNT_TYPE_GLOBAL;
- $options['backend'] = $backends[$options['class']]['backend'];
- $mountPoints[$mountPoint] = $options;
- }
+ foreach ($userStoragesService->getAllStorages() as $storage) {
+ $mountPoint = '/'.$uid.'/files'.$storage->getMountPoint();
+ $mountEntry = self::prepareMountPointEntry($storage, true);
+ foreach ($mountEntry['options'] as &$option) {
+ $option = self::setUserVars($uid, $option);
}
+ $mountPoints[$mountPoint] = $mountEntry;
}
- // Group mount points
- if (isset($mountConfig[self::MOUNT_TYPE_GROUP])) {
- foreach ($mountConfig[self::MOUNT_TYPE_GROUP] as $group => $mounts) {
- if (\OC_Group::inGroup($user, $group)) {
- foreach ($mounts as $mountPoint => $options) {
- $mountPoint = self::setUserVars($user, $mountPoint);
- foreach ($options as &$option) {
- $option = self::setUserVars($user, $option);
- }
- $options['personal'] = false;
- $options['options'] = self::decryptPasswords($options['options']);
- if (!isset($options['priority'])) {
- $options['priority'] = $backends[$options['class']]['priority'];
- }
-
- // Override if priority greater or if priority type different
- if ((!isset($mountPoints[$mountPoint]))
- || ($options['priority'] >= $mountPoints[$mountPoint]['priority'])
- || ($mountPoints[$mountPoint]['priority_type'] !== self::MOUNT_TYPE_GROUP)
- ) {
- $options['priority_type'] = self::MOUNT_TYPE_GROUP;
- $options['backend'] = $backends[$options['class']]['backend'];
- $mountPoints[$mountPoint] = $options;
- }
- }
- }
- }
- }
- // User mount points
- if (isset($mountConfig[self::MOUNT_TYPE_USER])) {
- foreach ($mountConfig[self::MOUNT_TYPE_USER] as $mountUser => $mounts) {
- if (strtolower($mountUser) === strtolower($user)) {
- foreach ($mounts as $mountPoint => $options) {
- $mountPoint = self::setUserVars($user, $mountPoint);
- foreach ($options as &$option) {
- $option = self::setUserVars($user, $option);
- }
- $options['personal'] = false;
- $options['options'] = self::decryptPasswords($options['options']);
- if (!isset($options['priority'])) {
- $options['priority'] = $backends[$options['class']]['priority'];
- }
-
- // Override if priority greater or if priority type different
- if ((!isset($mountPoints[$mountPoint]))
- || ($options['priority'] >= $mountPoints[$mountPoint]['priority'])
- || ($mountPoints[$mountPoint]['priority_type'] !== self::MOUNT_TYPE_USER)
- ) {
- $options['priority_type'] = self::MOUNT_TYPE_USER;
- $options['backend'] = $backends[$options['class']]['backend'];
- $mountPoints[$mountPoint] = $options;
- }
- }
- }
- }
- }
-
- $personalBackends = self::getPersonalBackends();
- // Load personal mount points
- $mountConfig = self::readData($user);
- if (isset($mountConfig[self::MOUNT_TYPE_USER][$user])) {
- foreach ($mountConfig[self::MOUNT_TYPE_USER][$user] as $mountPoint => $options) {
- if (isset($personalBackends[$options['class']])) {
- $options['personal'] = true;
- $options['options'] = self::decryptPasswords($options['options']);
-
- // Always override previous config
- $options['priority_type'] = self::MOUNT_TYPE_PERSONAL;
- $options['backend'] = $backends[$options['class']]['backend'];
- $mountPoints[$mountPoint] = $options;
- }
- }
- }
+ $userGlobalStoragesService->resetUser();
+ $userStoragesService->resetUser();
return $mountPoints;
}
/**
- * fill in the correct values for $user
+ * Get the system mount points
*
- * @param string $user user value
- * @param string|array $input
- * @return string
+ * @return array
+ *
+ * @deprecated 8.2.0 use GlobalStoragesService::getAllStorages()
*/
- private static function setUserVars($user, $input) {
- if (is_array($input)) {
- foreach ($input as &$value) {
- if (is_string($value)) {
- $value = str_replace('$user', $user, $value);
- }
- }
- } else {
- $input = str_replace('$user', $user, $input);
+ public static function getSystemMountPoints() {
+ $mountPoints = [];
+ $service = self::$app->getContainer()->query('OCA\Files_External\Service\GlobalStoragesService');
+
+ foreach ($service->getAllStorages() as $storage) {
+ $mountPoints[] = self::prepareMountPointEntry($storage, false);
}
- return $input;
}
-
/**
- * Get details on each of the external storage backends, used for the mount config UI
- * Some backends are not available as a personal backend, f.e. Local and such that have
- * been disabled by the admin.
- *
- * If a custom UI is needed, add the key 'custom' and a javascript file with that name will be loaded
- * If the configuration parameter should be secret, add a '*' to the beginning of the value
- * If the configuration parameter is a boolean, add a '!' to the beginning of the value
- * If the configuration parameter is optional, add a '&' to the beginning of the value
- * If the configuration parameter is hidden, add a '#' to the beginning of the value
+ * Get the personal mount points of the current user
*
* @return array
+ *
+ * @deprecated 8.2.0 use UserStoragesService::getAllStorages()
*/
- public static function getPersonalBackends() {
-
- // Check whether the user has permissions to add personal storage backends
- // return an empty array if this is not the case
- if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') !== 'yes') {
- return array();
- }
-
- $backEnds = self::getBackends();
-
- // Remove local storage and other disabled storages
- unset($backEnds['\OC\Files\Storage\Local']);
+ public static function getPersonalMountPoints() {
+ $mountPoints = [];
+ $service = self::$app->getContainer()->query('OCA\Files_External\Service\UserStoragesService');
- $allowedBackEnds = explode(',', OCP\Config::getAppValue('files_external', 'user_mounting_backends', ''));
- foreach ($backEnds as $backend => $null) {
- if (!in_array($backend, $allowedBackEnds)) {
- unset($backEnds[$backend]);
- }
+ foreach ($service->getAllStorages() as $storage) {
+ $mountPoints[] = self::prepareMountPointEntry($storage, true);
}
-
- return $backEnds;
}
/**
- * Get the system mount points
- * The returned array is not in the same format as getUserMountPoints()
+ * Convert a StorageConfig to the legacy mountPoints array format
+ * There's a lot of extra information in here, to satisfy all of the legacy functions
*
+ * @param StorageConfig $storage
+ * @param bool $isPersonal
* @return array
*/
- public static function getSystemMountPoints() {
- $mountPoints = self::readData();
- $backends = self::getBackends();
- $system = array();
- if (isset($mountPoints[self::MOUNT_TYPE_GROUP])) {
- foreach ($mountPoints[self::MOUNT_TYPE_GROUP] as $group => $mounts) {
- foreach ($mounts as $mountPoint => $mount) {
- // Update old classes to new namespace
- if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
- $mount['class'] = '\OC\Files\Storage\\' . substr($mount['class'], 15);
- }
- $mount['options'] = self::decryptPasswords($mount['options']);
- if (!isset($mount['priority'])) {
- $mount['priority'] = $backends[$mount['class']]['priority'];
- }
- // Remove '/$user/files/' from mount point
- $mountPoint = substr($mountPoint, 13);
-
- $config = array(
- 'class' => $mount['class'],
- 'mountpoint' => $mountPoint,
- 'backend' => $backends[$mount['class']]['backend'],
- 'priority' => $mount['priority'],
- 'options' => $mount['options'],
- 'applicable' => array('groups' => array($group), 'users' => array())
- );
- if (isset($mount['id'])) {
- $config['id'] = (int)$mount['id'];
- }
- if (isset($mount['storage_id'])) {
- $config['storage_id'] = (int)$mount['storage_id'];
- }
- if (isset($mount['mountOptions'])) {
- $config['mountOptions'] = $mount['mountOptions'];
- }
- $hash = self::makeConfigHash($config);
- // If an existing config exists (with same class, mountpoint and options)
- if (isset($system[$hash])) {
- // add the groups into that config
- $system[$hash]['applicable']['groups']
- = array_merge($system[$hash]['applicable']['groups'], array($group));
- } else {
- $system[$hash] = $config;
- }
- }
- }
- }
- if (isset($mountPoints[self::MOUNT_TYPE_USER])) {
- foreach ($mountPoints[self::MOUNT_TYPE_USER] as $user => $mounts) {
- foreach ($mounts as $mountPoint => $mount) {
- // Update old classes to new namespace
- if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
- $mount['class'] = '\OC\Files\Storage\\' . substr($mount['class'], 15);
- }
- $mount['options'] = self::decryptPasswords($mount['options']);
- if (!isset($mount['priority'])) {
- $mount['priority'] = $backends[$mount['class']]['priority'];
- }
- // Remove '/$user/files/' from mount point
- $mountPoint = substr($mountPoint, 13);
- $config = array(
- 'class' => $mount['class'],
- 'mountpoint' => $mountPoint,
- 'backend' => $backends[$mount['class']]['backend'],
- 'priority' => $mount['priority'],
- 'options' => $mount['options'],
- 'applicable' => array('groups' => array(), 'users' => array($user))
- );
- if (isset($mount['id'])) {
- $config['id'] = (int)$mount['id'];
- }
- if (isset($mount['storage_id'])) {
- $config['storage_id'] = (int)$mount['storage_id'];
- }
- if (isset($mount['mountOptions'])) {
- $config['mountOptions'] = $mount['mountOptions'];
- }
- $hash = self::makeConfigHash($config);
- // If an existing config exists (with same class, mountpoint and options)
- if (isset($system[$hash])) {
- // add the users into that config
- $system[$hash]['applicable']['users']
- = array_merge($system[$hash]['applicable']['users'], array($user));
- } else {
- $system[$hash] = $config;
- }
- }
- }
- }
- return array_values($system);
+ private static function prepareMountPointEntry(StorageConfig $storage, $isPersonal) {
+ $mountEntry = [];
+
+ $mountEntry['mountpoint'] = substr($storage->getMountPoint(), 1); // remove leading slash
+ $mountEntry['class'] = $storage->getBackend()->getIdentifier();
+ $mountEntry['backend'] = $storage->getBackend()->getText();
+ $mountEntry['authMechanism'] = $storage->getAuthMechanism()->getIdentifier();
+ $mountEntry['personal'] = $isPersonal;
+ $mountEntry['options'] = self::decryptPasswords($storage->getBackendOptions());
+ $mountEntry['mountOptions'] = $storage->getMountOptions();
+ $mountEntry['priority'] = $storage->getPriority();
+ $mountEntry['applicable'] = [
+ 'groups' => $storage->getApplicableGroups(),
+ 'users' => $storage->getApplicableUsers(),
+ ];
+ $mountEntry['id'] = $storage->getId();
+ // $mountEntry['storage_id'] = null; // we don't store this!
+
+ return $mountEntry;
}
/**
- * Get the personal mount points of the current user
- * The returned array is not in the same format as getUserMountPoints()
+ * fill in the correct values for $user
*
- * @return array
+ * @param string $user user value
+ * @param string|array $input
+ * @return string
*/
- public static function getPersonalMountPoints() {
- $mountPoints = self::readData(OCP\User::getUser());
- $backEnds = self::getBackends();
- $uid = OCP\User::getUser();
- $personal = array();
- if (isset($mountPoints[self::MOUNT_TYPE_USER][$uid])) {
- foreach ($mountPoints[self::MOUNT_TYPE_USER][$uid] as $mountPoint => $mount) {
- // Update old classes to new namespace
- if (strpos($mount['class'], 'OC_Filestorage_') !== false) {
- $mount['class'] = '\OC\Files\Storage\\' . substr($mount['class'], 15);
- }
- $mount['options'] = self::decryptPasswords($mount['options']);
- $config = array(
- 'class' => $mount['class'],
- // Remove '/uid/files/' from mount point
- 'mountpoint' => substr($mountPoint, strlen($uid) + 8),
- 'backend' => $backEnds[$mount['class']]['backend'],
- 'options' => $mount['options']
- );
- if (isset($mount['id'])) {
- $config['id'] = (int)$mount['id'];
- }
- if (isset($mount['storage_id'])) {
- $config['storage_id'] = (int)$mount['storage_id'];
- }
- if (isset($mount['mountOptions'])) {
- $config['mountOptions'] = $mount['mountOptions'];
+ public static function setUserVars($user, $input) {
+ if (is_array($input)) {
+ foreach ($input as &$value) {
+ if (is_string($value)) {
+ $value = str_replace('$user', $user, $value);
}
- $personal[] = $config;
}
+ } else {
+ $input = str_replace('$user', $user, $input);
}
- return $personal;
+ return $input;
}
/**
@@ -515,163 +268,6 @@ class OC_Mount_Config {
}
/**
- * Add a mount point to the filesystem
- *
- * @param string $mountPoint Mount point
- * @param string $class Backend class
- * @param array $classOptions Backend parameters for the class
- * @param string $mountType MOUNT_TYPE_GROUP | MOUNT_TYPE_USER
- * @param string $applicable User or group to apply mount to
- * @param bool $isPersonal Personal or system mount point i.e. is this being called from the personal or admin page
- * @param int|null $priority Mount point priority, null for default
- * @return boolean
- *
- * @deprecated use StoragesService#addStorage() instead
- */
- public static function addMountPoint($mountPoint,
- $class,
- $classOptions,
- $mountType,
- $applicable,
- $isPersonal = false,
- $priority = null) {
- $backends = self::getBackends();
- $mountPoint = OC\Files\Filesystem::normalizePath($mountPoint);
- $relMountPoint = $mountPoint;
- if ($mountPoint === '' || $mountPoint === '/') {
- // can't mount at root folder
- return false;
- }
-
- if (!isset($backends[$class])) {
- // invalid backend
- return false;
- }
- if ($isPersonal) {
- // Verify that the mount point applies for the current user
- // Prevent non-admin users from mounting local storage and other disabled backends
- $allowed_backends = self::getPersonalBackends();
- if ($applicable != OCP\User::getUser() || !isset($allowed_backends[$class])) {
- return false;
- }
- $mountPoint = '/' . $applicable . '/files/' . ltrim($mountPoint, '/');
- } else {
- $mountPoint = '/$user/files/' . ltrim($mountPoint, '/');
- }
-
- $mount = array($applicable => array(
- $mountPoint => array(
- 'class' => $class,
- 'options' => self::encryptPasswords($classOptions))
- )
- );
- if (!$isPersonal && !is_null($priority)) {
- $mount[$applicable][$mountPoint]['priority'] = $priority;
- }
-
- $mountPoints = self::readData($isPersonal ? OCP\User::getUser() : null);
- // who else loves multi-dimensional array ?
- $isNew = !isset($mountPoints[$mountType]) ||
- !isset($mountPoints[$mountType][$applicable]) ||
- !isset($mountPoints[$mountType][$applicable][$mountPoint]);
- $mountPoints = self::mergeMountPoints($mountPoints, $mount, $mountType);
-
- // Set default priority if none set
- if (!isset($mountPoints[$mountType][$applicable][$mountPoint]['priority'])) {
- if (isset($backends[$class]['priority'])) {
- $mountPoints[$mountType][$applicable][$mountPoint]['priority']
- = $backends[$class]['priority'];
- } else {
- $mountPoints[$mountType][$applicable][$mountPoint]['priority']
- = 100;
- }
- }
-
- self::writeData($isPersonal ? OCP\User::getUser() : null, $mountPoints);
-
- $result = self::getBackendStatus($class, $classOptions, $isPersonal);
- if ($result === self::STATUS_SUCCESS && $isNew) {
- \OC_Hook::emit(
- \OC\Files\Filesystem::CLASSNAME,
- \OC\Files\Filesystem::signal_create_mount,
- array(
- \OC\Files\Filesystem::signal_param_path => $relMountPoint,
- \OC\Files\Filesystem::signal_param_mount_type => $mountType,
- \OC\Files\Filesystem::signal_param_users => $applicable,
- )
- );
- }
- return $result;
- }
-
- /**
- *
- * @param string $mountPoint Mount point
- * @param string $mountType MOUNT_TYPE_GROUP | MOUNT_TYPE_USER
- * @param string $applicable User or group to remove mount from
- * @param bool $isPersonal Personal or system mount point
- * @return bool
- *
- * @deprecated use StoragesService#removeStorage() instead
- */
- public static function removeMountPoint($mountPoint, $mountType, $applicable, $isPersonal = false) {
- // Verify that the mount point applies for the current user
- $relMountPoints = $mountPoint;
- if ($isPersonal) {
- if ($applicable != OCP\User::getUser()) {
- return false;
- }
- $mountPoint = '/' . $applicable . '/files/' . ltrim($mountPoint, '/');
- } else {
- $mountPoint = '/$user/files/' . ltrim($mountPoint, '/');
- }
- $mountPoint = \OC\Files\Filesystem::normalizePath($mountPoint);
- $mountPoints = self::readData($isPersonal ? OCP\User::getUser() : null);
- // Remove mount point
- unset($mountPoints[$mountType][$applicable][$mountPoint]);
- // Unset parent arrays if empty
- if (empty($mountPoints[$mountType][$applicable])) {
- unset($mountPoints[$mountType][$applicable]);
- if (empty($mountPoints[$mountType])) {
- unset($mountPoints[$mountType]);
- }
- }
- self::writeData($isPersonal ? OCP\User::getUser() : null, $mountPoints);
- \OC_Hook::emit(
- \OC\Files\Filesystem::CLASSNAME,
- \OC\Files\Filesystem::signal_delete_mount,
- array(
- \OC\Files\Filesystem::signal_param_path => $relMountPoints,
- \OC\Files\Filesystem::signal_param_mount_type => $mountType,
- \OC\Files\Filesystem::signal_param_users => $applicable,
- )
- );
- return true;
- }
-
- /**
- *
- * @param string $mountPoint Mount point
- * @param string $target The new mount point
- * @param string $mountType MOUNT_TYPE_GROUP | MOUNT_TYPE_USER
- * @return bool
- */
- public static function movePersonalMountPoint($mountPoint, $target, $mountType) {
- $mountPoint = rtrim($mountPoint, '/');
- $user = OCP\User::getUser();
- $mountPoints = self::readData($user);
- if (!isset($mountPoints[$mountType][$user][$mountPoint])) {
- return false;
- }
- $mountPoints[$mountType][$user][$target] = $mountPoints[$mountType][$user][$mountPoint];
- // Remove old mount point
- unset($mountPoints[$mountType][$user][$mountPoint]);
-
- self::writeData($user, $mountPoints);
- return true;
- }
-
- /**
* Read the mount points in the config file into an array
*
* @param string|null $user If not null, personal for $user, otherwise system
@@ -721,74 +317,35 @@ class OC_Mount_Config {
}
/**
- * check dependencies
+ * Get backend dependency message
+ * TODO: move into AppFramework along with templates
+ *
+ * @param BackendConfig[] $backends
+ * @return string
*/
- public static function checkDependencies() {
- $dependencies = array();
- foreach (OC_Mount_Config::$backends as $class => $backend) {
- if (isset($backend['has_dependencies']) and $backend['has_dependencies'] === true) {
- $result = $class::checkDependencies();
- if ($result !== true) {
- if (!is_array($result)) {
- $result = array($result);
- }
- foreach ($result as $key => $value) {
- if (is_numeric($key)) {
- OC_Mount_Config::addDependency($dependencies, $value, $backend['backend']);
- } else {
- OC_Mount_Config::addDependency($dependencies, $key, $backend['backend'], $value);
- }
- }
- }
- }
- }
-
- if (count($dependencies) > 0) {
- return OC_Mount_Config::generateDependencyMessage($dependencies);
- }
- return '';
- }
-
- private static function addDependency(&$dependencies, $module, $backend, $message = null) {
- if (!isset($dependencies[$module])) {
- $dependencies[$module] = array();
- }
-
- if ($message === null) {
- $dependencies[$module][] = $backend;
- } else {
- $dependencies[$module][] = array('backend' => $backend, 'message' => $message);
- }
- }
-
- private static function generateDependencyMessage($dependencies) {
+ public static function dependencyMessage($backends) {
$l = new \OC_L10N('files_external');
- $dependencyMessage = '';
- foreach ($dependencies as $module => $backends) {
- $dependencyGroup = array();
- foreach ($backends as $backend) {
- if (is_array($backend)) {
- $dependencyMessage .= '<br />' . $l->t('<b>Note:</b> ') . $backend['message'];
+ $message = '';
+ $dependencyGroups = [];
+
+ foreach ($backends as $backend) {
+ foreach ($backend->checkDependencies() as $dependency) {
+ if ($message = $dependency->getMessage()) {
+ $message .= '<br />' . $l->t('<b>Note:</b> ') . $message;
} else {
- $dependencyGroup[] = $backend;
+ $dependencyGroups[$dependency->getDependency()][] = $backend;
}
}
+ }
- $dependencyGroupCount = count($dependencyGroup);
- if ($dependencyGroupCount > 0) {
- $backends = '';
- for ($i = 0; $i < $dependencyGroupCount; $i++) {
- if ($i > 0 && $i === $dependencyGroupCount - 1) {
- $backends .= ' ' . $l->t('and') . ' ';
- } elseif ($i > 0) {
- $backends .= ', ';
- }
- $backends .= '<i>' . $dependencyGroup[$i] . '</i>';
- }
- $dependencyMessage .= '<br />' . OC_Mount_Config::getSingleDependencyMessage($l, $module, $backends);
- }
+ foreach ($dependencyGroups as $module => $dependants) {
+ $backends = implode(', ', array_map(function($backend) {
+ return '<i>' . $backend->getText() . '</i>';
+ }, $dependants));
+ $message .= '<br />' . OC_Mount_Config::getSingleDependencyMessage($l, $module, $backends);
}
- return $dependencyMessage;
+
+ return $message;
}
/**
@@ -918,7 +475,8 @@ class OC_Mount_Config {
public static function makeConfigHash($config) {
$data = json_encode(
array(
- 'c' => $config['class'],
+ 'c' => $config['backend'],
+ 'a' => $config['authMechanism'],
'm' => $config['mountpoint'],
'o' => $config['options'],
'p' => isset($config['priority']) ? $config['priority'] : -1,
@@ -967,7 +525,8 @@ class OC_Mount_Config {
return false;
}
- $class = $options['class'];
+ $service = self::$app->getContainer()->query('OCA\Files_External\Service\BackendService');
+ $class = $service->getBackend($options['backend'])->getStorageClass();
try {
/** @var \OC\Files\Storage\Storage $storage */
$storage = new $class($options['options']);
diff --git a/apps/files_external/lib/config/configadapter.php b/apps/files_external/lib/config/configadapter.php
index b5c2ba4fc92..a15d9e06a5f 100644
--- a/apps/files_external/lib/config/configadapter.php
+++ b/apps/files_external/lib/config/configadapter.php
@@ -2,6 +2,7 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
@@ -22,16 +23,81 @@
namespace OCA\Files_External\Config;
+use OCP\Files\Storage;
use OC\Files\Mount\MountPoint;
use OCP\Files\Storage\IStorageFactory;
-use OCA\Files_External\PersonalMount;
+use OCA\Files_External\Lib\PersonalMount;
use OCP\Files\Config\IMountProvider;
use OCP\IUser;
+use OCA\Files_external\Service\UserStoragesService;
+use OCA\Files_External\Service\UserGlobalStoragesService;
+use OCA\Files_External\Lib\StorageConfig;
+use OCP\Files\StorageNotAvailableException;
+use OCA\Files_External\Lib\FailedStorage;
/**
* Make the old files_external config work with the new public mount config api
*/
class ConfigAdapter implements IMountProvider {
+
+ /** @var UserStoragesService */
+ private $userStoragesService;
+
+ /** @var UserGlobalStoragesService */
+ private $userGlobalStoragesService;
+
+ /**
+ * @param UserStoragesService $userStoragesService
+ * @param UserGlobalStoragesService $userGlobalStoragesService
+ */
+ public function __construct(
+ UserStoragesService $userStoragesService,
+ UserGlobalStoragesService $userGlobalStoragesService
+ ) {
+ $this->userStoragesService = $userStoragesService;
+ $this->userGlobalStoragesService = $userGlobalStoragesService;
+ }
+
+ /**
+ * Process storage ready for mounting
+ *
+ * @param StorageConfig $storage
+ * @param IUser $user
+ */
+ private function prepareStorageConfig(StorageConfig &$storage, IUser $user) {
+ foreach ($storage->getBackendOptions() as $option => $value) {
+ $storage->setBackendOption($option, \OC_Mount_Config::setUserVars(
+ $user->getUID(), $value
+ ));
+ }
+
+ $objectStore = $storage->getBackendOption('objectstore');
+ if ($objectStore) {
+ $objectClass = $objectStore['class'];
+ $storage->setBackendOption('objectstore', new $objectClass($objectStore));
+ }
+
+ $storage->getAuthMechanism()->manipulateStorageConfig($storage);
+ $storage->getBackend()->manipulateStorageConfig($storage);
+ }
+
+ /**
+ * Construct the storage implementation
+ *
+ * @param StorageConfig $storageConfig
+ * @return Storage
+ */
+ private function constructStorage(StorageConfig $storageConfig) {
+ $class = $storageConfig->getBackend()->getStorageClass();
+ $storage = new $class($storageConfig->getBackendOptions());
+
+ // auth mechanism should fire first
+ $storage = $storageConfig->getBackend()->wrapStorage($storage);
+ $storage = $storageConfig->getAuthMechanism()->wrapStorage($storage);
+
+ return $storage;
+ }
+
/**
* Get all mountpoints applicable for the user
*
@@ -40,20 +106,54 @@ class ConfigAdapter implements IMountProvider {
* @return \OCP\Files\Mount\IMountPoint[]
*/
public function getMountsForUser(IUser $user, IStorageFactory $loader) {
- $mountPoints = \OC_Mount_Config::getAbsoluteMountPoints($user->getUID());
- $mounts = array();
- foreach ($mountPoints as $mountPoint => $options) {
- if (isset($options['options']['objectstore'])) {
- $objectClass = $options['options']['objectstore']['class'];
- $options['options']['objectstore'] = new $objectClass($options['options']['objectstore']);
+ $mounts = [];
+
+ $this->userStoragesService->setUser($user);
+ $this->userGlobalStoragesService->setUser($user);
+
+ foreach ($this->userGlobalStoragesService->getAllStorages() as $storage) {
+ try {
+ $this->prepareStorageConfig($storage, $user);
+ $impl = $this->constructStorage($storage);
+ } catch (\Exception $e) {
+ // propagate exception into filesystem
+ $impl = new FailedStorage(['exception' => $e]);
}
- $mountOptions = isset($options['mountOptions']) ? $options['mountOptions'] : [];
- if (isset($options['personal']) && $options['personal']) {
- $mounts[] = new PersonalMount($options['class'], $mountPoint, $options['options'], $loader, $mountOptions);
- } else {
- $mounts[] = new MountPoint($options['class'], $mountPoint, $options['options'], $loader, $mountOptions);
+
+ $mount = new MountPoint(
+ $impl,
+ '/'.$user->getUID().'/files' . $storage->getMountPoint(),
+ null,
+ $loader,
+ $storage->getMountOptions()
+ );
+ $mounts[$storage->getMountPoint()] = $mount;
+ }
+
+ foreach ($this->userStoragesService->getAllStorages() as $storage) {
+ try {
+ $this->prepareStorageConfig($storage, $user);
+ $impl = $this->constructStorage($storage);
+ } catch (\Exception $e) {
+ // propagate exception into filesystem
+ $impl = new FailedStorage(['exception' => $e]);
}
+
+ $mount = new PersonalMount(
+ $this->userStoragesService,
+ $storage->getId(),
+ $impl,
+ '/'.$user->getUID().'/files' . $storage->getMountPoint(),
+ null,
+ $loader,
+ $storage->getMountOptions()
+ );
+ $mounts[$storage->getMountPoint()] = $mount;
}
+
+ $this->userStoragesService->resetUser();
+ $this->userGlobalStoragesService->resetUser();
+
return $mounts;
}
}
diff --git a/apps/files_external/lib/definitionparameter.php b/apps/files_external/lib/definitionparameter.php
new file mode 100644
index 00000000000..4b560908b69
--- /dev/null
+++ b/apps/files_external/lib/definitionparameter.php
@@ -0,0 +1,179 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib;
+
+/**
+ * Parameter for an external storage definition
+ */
+class DefinitionParameter implements \JsonSerializable {
+
+ /** Value constants */
+ const VALUE_TEXT = 0;
+ const VALUE_BOOLEAN = 1;
+ const VALUE_PASSWORD = 2;
+ const VALUE_HIDDEN = 3;
+
+ /** Flag constants */
+ const FLAG_NONE = 0;
+ const FLAG_OPTIONAL = 1;
+
+ /** @var string name of parameter */
+ private $name;
+
+ /** @var string human-readable parameter text */
+ private $text;
+
+ /** @var int value type, see self::VALUE_* constants */
+ private $type = self::VALUE_TEXT;
+
+ /** @var int flags, see self::FLAG_* constants */
+ private $flags = self::FLAG_NONE;
+
+ /**
+ * @param string $name
+ * @param string $text
+ */
+ public function __construct($name, $text) {
+ $this->name = $name;
+ $this->text = $text;
+ }
+
+ /**
+ * @return string
+ */
+ public function getName() {
+ return $this->name;
+ }
+
+ /**
+ * @return string
+ */
+ public function getText() {
+ return $this->text;
+ }
+
+ /**
+ * Get value type
+ *
+ * @return int
+ */
+ public function getType() {
+ return $this->type;
+ }
+
+ /**
+ * Set value type
+ *
+ * @param int $type
+ * @return self
+ */
+ public function setType($type) {
+ $this->type = $type;
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function getFlags() {
+ return $this->flags;
+ }
+
+ /**
+ * @param int $flags
+ * @return self
+ */
+ public function setFlags($flags) {
+ $this->flags = $flags;
+ return $this;
+ }
+
+ /**
+ * @param int $flag
+ * @return self
+ */
+ public function setFlag($flag) {
+ $this->flags |= $flag;
+ return $this;
+ }
+
+ /**
+ * @param int $flag
+ * @return bool
+ */
+ public function isFlagSet($flag) {
+ return (bool) $this->flags & $flag;
+ }
+
+ /**
+ * Serialize into JSON for client-side JS
+ *
+ * @return string
+ */
+ public function jsonSerialize() {
+ $prefix = '';
+ switch ($this->getType()) {
+ case self::VALUE_BOOLEAN:
+ $prefix = '!';
+ break;
+ case self::VALUE_PASSWORD:
+ $prefix = '*';
+ break;
+ case self::VALUE_HIDDEN:
+ $prefix = '#';
+ break;
+ }
+
+ switch ($this->getFlags()) {
+ case self::FLAG_OPTIONAL:
+ $prefix = '&' . $prefix;
+ break;
+ }
+
+ return $prefix . $this->getText();
+ }
+
+ /**
+ * Validate a parameter value against this
+ *
+ * @param mixed $value Value to check
+ * @return bool success
+ */
+ public function validateValue($value) {
+ if ($this->getFlags() & self::FLAG_OPTIONAL) {
+ return true;
+ }
+ switch ($this->getType()) {
+ case self::VALUE_BOOLEAN:
+ if (!is_bool($value)) {
+ return false;
+ }
+ break;
+ default:
+ if (empty($value)) {
+ return false;
+ }
+ break;
+ }
+ return true;
+ }
+}
diff --git a/apps/files_external/lib/dependencytrait.php b/apps/files_external/lib/dependencytrait.php
new file mode 100644
index 00000000000..116421eab14
--- /dev/null
+++ b/apps/files_external/lib/dependencytrait.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib;
+
+use \OCA\Files_External\Lib\MissingDependency;
+
+/**
+ * Trait for objects that have dependencies for use
+ */
+trait DependencyTrait {
+
+ /** @var callable|null dependency check */
+ private $dependencyCheck = null;
+
+ /**
+ * @return bool
+ */
+ public function hasDependencies() {
+ return !is_null($this->dependencyCheck);
+ }
+
+ /**
+ * @param callable $dependencyCheck
+ * @return self
+ */
+ public function setDependencyCheck(callable $dependencyCheck) {
+ $this->dependencyCheck = $dependencyCheck;
+ return $this;
+ }
+
+ /**
+ * Check if object is valid for use
+ *
+ * @return MissingDependency[] Unsatisfied dependencies
+ */
+ public function checkDependencies() {
+ $ret = [];
+
+ if ($this->hasDependencies()) {
+ $result = call_user_func($this->dependencyCheck);
+ if ($result !== true) {
+ if (!is_array($result)) {
+ $result = [$result];
+ }
+ foreach ($result as $key => $value) {
+ if (!($value instanceof MissingDependency)) {
+ $module = null;
+ $message = null;
+ if (is_numeric($key)) {
+ $module = $value;
+ } else {
+ $module = $key;
+ $message = $value;
+ }
+ $value = new MissingDependency($module, $this);
+ $value->setMessage($message);
+ }
+ $ret[] = $value;
+ }
+ }
+ }
+
+ return $ret;
+ }
+
+}
+
diff --git a/apps/files_external/lib/failedstorage.php b/apps/files_external/lib/failedstorage.php
new file mode 100644
index 00000000000..6afa98052c2
--- /dev/null
+++ b/apps/files_external/lib/failedstorage.php
@@ -0,0 +1,200 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib;
+
+use \OCP\Lock\ILockingProvider;
+use \OC\Files\Storage\Common;
+use \OCP\Files\StorageNotAvailableException;
+
+/**
+ * Storage placeholder to represent a missing precondition, storage unavailable
+ */
+class FailedStorage extends Common {
+
+ /** @var \Exception */
+ protected $e;
+
+ /**
+ * @param array $params ['exception' => \Exception]
+ */
+ public function __construct($params) {
+ $this->e = $params['exception'];
+ }
+
+ public function getId() {
+ // we can't return anything sane here
+ return 'failedstorage';
+ }
+
+ public function mkdir($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function rmdir($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function opendir($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function is_dir($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function is_file($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function stat($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function filetype($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function filesize($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function isCreatable($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function isReadable($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function isUpdatable($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function isDeletable($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function isSharable($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function getPermissions($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function file_exists($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function filemtime($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function file_get_contents($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function file_put_contents($path, $data) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function unlink($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function rename($path1, $path2) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function copy($path1, $path2) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function fopen($path, $mode) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function getMimeType($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function hash($type, $path, $raw = false) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function free_space($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function search($query) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function touch($path, $mtime = null) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function getLocalFile($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function getLocalFolder($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function hasUpdated($path, $time) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function getETag($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function getDirectDownload($path) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function verifyPath($path, $fileName) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function acquireLock($path, $type, ILockingProvider $provider) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function releaseLock($path, $type, ILockingProvider $provider) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+ public function changeLock($path, $type, ILockingProvider $provider) {
+ throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
+ }
+
+}
diff --git a/apps/files_external/lib/frontenddefinitiontrait.php b/apps/files_external/lib/frontenddefinitiontrait.php
new file mode 100644
index 00000000000..4b826372d2f
--- /dev/null
+++ b/apps/files_external/lib/frontenddefinitiontrait.php
@@ -0,0 +1,147 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib;
+
+use \OCA\Files_External\Lib\DefinitionParameter;
+use \OCA\Files_External\Lib\StorageConfig;
+
+/**
+ * Trait for objects that have a frontend representation
+ */
+trait FrontendDefinitionTrait {
+
+ /** @var string human-readable mechanism name */
+ private $text;
+
+ /** @var DefinitionParameter[] parameters for mechanism */
+ private $parameters = [];
+
+ /** @var string|null custom JS */
+ private $customJs = null;
+
+ /**
+ * @return string
+ */
+ public function getText() {
+ return $this->text;
+ }
+
+ /**
+ * @param string $text
+ * @return self
+ */
+ public function setText($text) {
+ $this->text = $text;
+ return $this;
+ }
+
+ /**
+ * @param FrontendDefinitionTrait $a
+ * @param FrontendDefinitionTrait $b
+ * @return int
+ */
+ public static function lexicalCompare(FrontendDefinitionTrait $a, FrontendDefinitionTrait $b) {
+ return strcmp($a->getText(), $b->getText());
+ }
+
+ /**
+ * @return DefinitionParameter[]
+ */
+ public function getParameters() {
+ return $this->parameters;
+ }
+
+ /**
+ * @param DefinitionParameter[] $parameters
+ * @return self
+ */
+ public function addParameters(array $parameters) {
+ foreach ($parameters as $parameter) {
+ $this->addParameter($parameter);
+ }
+ return $this;
+ }
+
+ /**
+ * @param DefinitionParameter $parameter
+ * @return self
+ */
+ public function addParameter(DefinitionParameter $parameter) {
+ $this->parameters[$parameter->getName()] = $parameter;
+ return $this;
+ }
+
+ /**
+ * @return string|null
+ */
+ public function getCustomJs() {
+ return $this->customJs;
+ }
+
+ /**
+ * @param string $custom
+ * @return self
+ */
+ public function setCustomJs($custom) {
+ $this->customJs = $custom;
+ return $this;
+ }
+
+ /**
+ * Serialize into JSON for client-side JS
+ *
+ * @return array
+ */
+ public function jsonSerializeDefinition() {
+ $configuration = [];
+ foreach ($this->getParameters() as $parameter) {
+ $configuration[$parameter->getName()] = $parameter;
+ }
+
+ $data = [
+ 'name' => $this->getText(),
+ 'configuration' => $configuration,
+ ];
+ if (isset($this->customJs)) {
+ $data['custom'] = $this->getCustomJs();
+ }
+ return $data;
+ }
+
+ /**
+ * Check if parameters are satisfied in a StorageConfig
+ *
+ * @param StorageConfig $storage
+ * @return bool
+ */
+ public function validateStorageDefinition(StorageConfig $storage) {
+ $options = $storage->getBackendOptions();
+ foreach ($this->getParameters() as $name => $parameter) {
+ $value = isset($options[$name]) ? $options[$name] : null;
+ if (!$parameter->validateValue($value)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/apps/files_external/lib/identifiertrait.php b/apps/files_external/lib/identifiertrait.php
new file mode 100644
index 00000000000..139911580fc
--- /dev/null
+++ b/apps/files_external/lib/identifiertrait.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib;
+
+/**
+ * Trait for objects requiring an identifier (and/or identifier aliases)
+ */
+trait IdentifierTrait {
+
+ /** @var string */
+ protected $identifier;
+
+ /** @var string[] */
+ protected $identifierAliases = [];
+
+ /**
+ * @return string
+ */
+ public function getIdentifier() {
+ return $this->identifier;
+ }
+
+ /**
+ * @param string $identifier
+ * @return self
+ */
+ public function setIdentifier($identifier) {
+ $this->identifier = $identifier;
+ $this->identifierAliases[] = $identifier;
+ return $this;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getIdentifierAliases() {
+ return $this->identifierAliases;
+ }
+
+ /**
+ * @param string $alias
+ * @return self
+ */
+ public function addIdentifierAlias($alias) {
+ $this->identifierAliases[] = $alias;
+ return $this;
+ }
+
+}
diff --git a/apps/files_external/lib/insufficientdataformeaningfulanswerexception.php b/apps/files_external/lib/insufficientdataformeaningfulanswerexception.php
new file mode 100644
index 00000000000..dd4cd75df12
--- /dev/null
+++ b/apps/files_external/lib/insufficientdataformeaningfulanswerexception.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib;
+
+use \OCP\Files\StorageNotAvailableException;
+
+/**
+ * Authentication mechanism or backend has insufficient data
+ */
+class InsufficientDataForMeaningfulAnswerException extends StorageNotAvailableException {
+}
diff --git a/apps/files_external/lib/missingdependency.php b/apps/files_external/lib/missingdependency.php
new file mode 100644
index 00000000000..9b25aeacc9b
--- /dev/null
+++ b/apps/files_external/lib/missingdependency.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib;
+
+/**
+ * External storage backend dependency
+ */
+class MissingDependency {
+
+ /** @var string */
+ private $dependency;
+
+ /** @var string|null Custom message */
+ private $message = null;
+
+ /**
+ * @param string $dependency
+ */
+ public function __construct($dependency) {
+ $this->dependency = $dependency;
+ }
+
+ /**
+ * @return string
+ */
+ public function getDependency() {
+ return $this->dependency;
+ }
+
+ /**
+ * @return string|null
+ */
+ public function getMessage() {
+ return $this->message;
+ }
+
+ /**
+ * @param string $message
+ * @return self
+ */
+ public function setMessage($message) {
+ $this->message = $message;
+ return $this;
+ }
+}
diff --git a/apps/files_external/lib/personalmount.php b/apps/files_external/lib/personalmount.php
index bbffc958641..d177f1a1ad0 100644
--- a/apps/files_external/lib/personalmount.php
+++ b/apps/files_external/lib/personalmount.php
@@ -20,15 +20,45 @@
*
*/
-namespace OCA\Files_External;
+namespace OCA\Files_External\Lib;
use OC\Files\Mount\MountPoint;
use OC\Files\Mount\MoveableMount;
+use OCA\Files_External\Service\UserStoragesService;
/**
* Person mount points can be moved by the user
*/
class PersonalMount extends MountPoint implements MoveableMount {
+ /** @var UserStoragesService */
+ protected $storagesService;
+
+ /** @var int */
+ protected $storageId;
+
+ /**
+ * @param UserStoragesService $storagesService
+ * @param int $storageId
+ * @param string|\OC\Files\Storage\Storage $storage
+ * @param string $mountpoint
+ * @param array $arguments (optional) configuration for the storage backend
+ * @param \OCP\Files\Storage\IStorageFactory $loader
+ * @param array $mountOptions mount specific options
+ */
+ public function __construct(
+ UserStoragesService $storagesService,
+ $storageId,
+ $storage,
+ $mountpoint,
+ $arguments = null,
+ $loader = null,
+ $mountOptions = null
+ ) {
+ parent::__construct($storage, $mountpoint, $arguments, $loader, $mountOptions);
+ $this->storagesService = $storagesService;
+ $this->storageId = $storageId;
+ }
+
/**
* Move the mount point to $target
*
@@ -36,9 +66,13 @@ class PersonalMount extends MountPoint implements MoveableMount {
* @return bool
*/
public function moveMount($target) {
- $result = \OC_Mount_Config::movePersonalMountPoint($this->getMountPoint(), $target, \OC_Mount_Config::MOUNT_TYPE_USER);
+ $storage = $this->storagesService->getStorage($this->storageId);
+ // remove "/$user/files" prefix
+ $targetParts = explode('/', trim($target, '/'), 3);
+ $storage->setMountPoint($targetParts[2]);
+ $this->storagesService->updateStorage($storage);
$this->setMountPoint($target);
- return $result;
+ return true;
}
/**
@@ -47,8 +81,7 @@ class PersonalMount extends MountPoint implements MoveableMount {
* @return bool
*/
public function removeMount() {
- $user = \OCP\User::getUser();
- $relativeMountPoint = substr($this->getMountPoint(), strlen('/' . $user . '/files/'));
- return \OC_Mount_Config::removeMountPoint($relativeMountPoint, \OC_Mount_Config::MOUNT_TYPE_USER, $user , true);
+ $this->storagesService->removeStorage($this->storageId);
+ return true;
}
}
diff --git a/apps/files_external/lib/prioritytrait.php b/apps/files_external/lib/prioritytrait.php
new file mode 100644
index 00000000000..22f9fe275d8
--- /dev/null
+++ b/apps/files_external/lib/prioritytrait.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib;
+
+use \OCA\Files_External\Service\BackendService;
+
+/**
+ * Trait to implement priority mechanics for a configuration class
+ */
+trait PriorityTrait {
+
+ /** @var int initial priority */
+ protected $priority = BackendService::PRIORITY_DEFAULT;
+
+ /**
+ * @return int
+ */
+ public function getPriority() {
+ return $this->priority;
+ }
+
+ /**
+ * @param int $priority
+ * @return self
+ */
+ public function setPriority($priority) {
+ $this->priority = $priority;
+ return $this;
+ }
+
+ /**
+ * @param PriorityTrait $a
+ * @param PriorityTrait $b
+ * @return int
+ */
+ public static function priorityCompare(PriorityTrait $a, PriorityTrait $b) {
+ return ($a->getPriority() - $b->getPriority());
+ }
+
+}
+
diff --git a/apps/files_external/lib/storageconfig.php b/apps/files_external/lib/storageconfig.php
index 92c27701d80..aeb8f527078 100644
--- a/apps/files_external/lib/storageconfig.php
+++ b/apps/files_external/lib/storageconfig.php
@@ -21,6 +21,9 @@
namespace OCA\Files_external\Lib;
+use \OCA\Files_External\Lib\Backend\Backend;
+use \OCA\Files_External\Lib\Auth\AuthMechanism;
+
/**
* External storage configuration
*/
@@ -34,11 +37,18 @@ class StorageConfig implements \JsonSerializable {
private $id;
/**
- * Backend class name
+ * Backend
*
- * @var string
+ * @var Backend
*/
- private $backendClass;
+ private $backend;
+
+ /**
+ * Authentication mechanism
+ *
+ * @var AuthMechanism
+ */
+ private $authMechanism;
/**
* Backend options
@@ -138,21 +148,31 @@ class StorageConfig implements \JsonSerializable {
}
/**
- * Returns the external storage backend class name
- *
- * @return string external storage backend class name
+ * @return Backend
*/
- public function getBackendClass() {
- return $this->backendClass;
+ public function getBackend() {
+ return $this->backend;
}
/**
- * Sets the external storage backend class name
- *
- * @param string external storage backend class name
+ * @param Backend
+ */
+ public function setBackend(Backend $backend) {
+ $this->backend= $backend;
+ }
+
+ /**
+ * @return AuthMechanism
*/
- public function setBackendClass($backendClass) {
- $this->backendClass = $backendClass;
+ public function getAuthMechanism() {
+ return $this->authMechanism;
+ }
+
+ /**
+ * @param AuthMechanism
+ */
+ public function setAuthMechanism(AuthMechanism $authMechanism) {
+ $this->authMechanism = $authMechanism;
}
/**
@@ -174,6 +194,25 @@ class StorageConfig implements \JsonSerializable {
}
/**
+ * @param string $key
+ * @return mixed
+ */
+ public function getBackendOption($key) {
+ if (isset($this->backendOptions[$key])) {
+ return $this->backendOptions[$key];
+ }
+ return null;
+ }
+
+ /**
+ * @param string $key
+ * @param mixed $value
+ */
+ public function setBackendOption($key, $value) {
+ $this->backendOptions[$key] = $value;
+ }
+
+ /**
* Returns the mount priority
*
* @return int priority
@@ -283,7 +322,8 @@ class StorageConfig implements \JsonSerializable {
$result['id'] = $this->id;
}
$result['mountPoint'] = $this->mountPoint;
- $result['backendClass'] = $this->backendClass;
+ $result['backend'] = $this->backend->getIdentifier();
+ $result['authMechanism'] = $this->authMechanism->getIdentifier();
$result['backendOptions'] = $this->backendOptions;
if (!is_null($this->priority)) {
$result['priority'] = $this->priority;
diff --git a/apps/files_external/lib/storagemodifiertrait.php b/apps/files_external/lib/storagemodifiertrait.php
new file mode 100644
index 00000000000..3af0bb234d9
--- /dev/null
+++ b/apps/files_external/lib/storagemodifiertrait.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib;
+
+use \OCP\Files\Storage;
+use \OCA\Files_External\Lib\StorageConfig;
+use \OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException;
+use \OCP\Files\StorageNotAvailableException;
+
+/**
+ * Trait for objects that can modify StorageConfigs and wrap Storages
+ *
+ * When a storage implementation is being prepared for use, the StorageConfig
+ * is passed through manipulateStorageConfig() to update any parameters as
+ * necessary. After the storage implementation has been constructed, it is
+ * passed through wrapStorage(), potentially replacing the implementation with
+ * a wrapped storage that changes its behaviour.
+ *
+ * Certain configuration options need to be set before the implementation is
+ * constructed, while others are retrieved directly from the storage
+ * implementation and so need a wrapper to be modified.
+ */
+trait StorageModifierTrait {
+
+ /**
+ * Modify a StorageConfig parameters
+ *
+ * @param StorageConfig $storage
+ * @throws InsufficientDataForMeaningfulAnswerException
+ * @throws StorageNotAvailableException
+ */
+ public function manipulateStorageConfig(StorageConfig &$storage) {
+ }
+
+ /**
+ * Wrap a Storage if necessary
+ *
+ * @param Storage $storage
+ * @return Storage
+ * @throws InsufficientDataForMeaningfulAnswerException
+ * @throws StorageNotAvailableException
+ */
+ public function wrapStorage(Storage $storage) {
+ return $storage;
+ }
+
+}
+
diff --git a/apps/files_external/lib/visibilitytrait.php b/apps/files_external/lib/visibilitytrait.php
new file mode 100644
index 00000000000..dfd2d323ca6
--- /dev/null
+++ b/apps/files_external/lib/visibilitytrait.php
@@ -0,0 +1,136 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Lib;
+
+use \OCA\Files_External\Service\BackendService;
+
+/**
+ * Trait to implement visibility mechanics for a configuration class
+ *
+ * The standard visibility defines which users/groups can use or see the
+ * object. The allowed visibility defines the maximum visibility allowed to be
+ * set on the object. The standard visibility is often set dynamically by
+ * stored configuration parameters that can be modified by the administrator,
+ * while the allowed visibility is set directly by the object and cannot be
+ * modified by the administrator.
+ */
+trait VisibilityTrait {
+
+ /** @var int visibility */
+ protected $visibility = BackendService::VISIBILITY_DEFAULT;
+
+ /** @var int allowed visibilities */
+ protected $allowedVisibility = BackendService::VISIBILITY_DEFAULT;
+
+ /**
+ * @return int
+ */
+ public function getVisibility() {
+ return $this->visibility;
+ }
+
+ /**
+ * Check if the backend is visible for a user type
+ *
+ * @param int $visibility
+ * @return bool
+ */
+ public function isVisibleFor($visibility) {
+ if ($this->visibility & $visibility) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param int $visibility
+ * @return self
+ */
+ public function setVisibility($visibility) {
+ $this->visibility = $visibility;
+ $this->allowedVisibility |= $visibility;
+ return $this;
+ }
+
+ /**
+ * @param int $visibility
+ * @return self
+ */
+ public function addVisibility($visibility) {
+ return $this->setVisibility($this->visibility | $visibility);
+ }
+
+ /**
+ * @param int $visibility
+ * @return self
+ */
+ public function removeVisibility($visibility) {
+ return $this->setVisibility($this->visibility & ~$visibility);
+ }
+
+ /**
+ * @return int
+ */
+ public function getAllowedVisibility() {
+ return $this->allowedVisibility;
+ }
+
+ /**
+ * Check if the backend is allowed to be visible for a user type
+ *
+ * @param int $allowedVisibility
+ * @return bool
+ */
+ public function isAllowedVisibleFor($allowedVisibility) {
+ if ($this->allowedVisibility & $allowedVisibility) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param int $allowedVisibility
+ * @return self
+ */
+ public function setAllowedVisibility($allowedVisibility) {
+ $this->allowedVisibility = $allowedVisibility;
+ $this->visibility &= $allowedVisibility;
+ return $this;
+ }
+
+ /**
+ * @param int $allowedVisibility
+ * @return self
+ */
+ public function addAllowedVisibility($allowedVisibility) {
+ return $this->setAllowedVisibility($this->allowedVisibility | $allowedVisibility);
+ }
+
+ /**
+ * @param int $allowedVisibility
+ * @return self
+ */
+ public function removeAllowedVisibility($allowedVisibility) {
+ return $this->setAllowedVisibility($this->allowedVisibility & ~$allowedVisibility);
+ }
+
+}
diff --git a/apps/files_external/personal.php b/apps/files_external/personal.php
index 1ac0f65a1f0..8717d91d4f1 100644
--- a/apps/files_external/personal.php
+++ b/apps/files_external/personal.php
@@ -24,34 +24,34 @@
*
*/
+use \OCA\Files_External\Service\BackendService;
+
+// we must use the same container
+$appContainer = \OC_Mount_Config::$app->getContainer();
+$backendService = $appContainer->query('OCA\Files_External\Service\BackendService');
+$userStoragesService = $appContainer->query('OCA\Files_external\Service\UserStoragesService');
+
OCP\Util::addScript('files_external', 'settings');
OCP\Util::addStyle('files_external', 'settings');
-$backends = OC_Mount_Config::getPersonalBackends();
-$mounts = OC_Mount_Config::getPersonalMountPoints();
-$hasId = true;
-foreach ($mounts as $mount) {
- if (!isset($mount['id'])) {
- // some mount points are missing ids
- $hasId = false;
- break;
+$backends = $backendService->getBackendsVisibleFor(BackendService::VISIBILITY_PERSONAL);
+$authMechanisms = $backendService->getAuthMechanismsVisibleFor(BackendService::VISIBILITY_PERSONAL);
+foreach ($backends as $backend) {
+ if ($backend->getCustomJs()) {
+ \OCP\Util::addScript('files_external', $backend->getCustomJs());
}
}
-
-if (!$hasId) {
- $service = new \OCA\Files_external\Service\UserStoragesService(\OC::$server->getUserSession());
- // this will trigger the new storage code which will automatically
- // generate storage config ids
- $service->getAllStorages();
- // re-read updated config
- $mounts = OC_Mount_Config::getPersonalMountPoints();
- // TODO: use the new storage config format in the template
+foreach ($authMechanisms as $authMechanism) {
+ if ($authMechanism->getCustomJs()) {
+ \OCP\Util::addScript('files_external', $authMechanism->getCustomJs());
+ }
}
$tmpl = new OCP\Template('files_external', 'settings');
$tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled());
$tmpl->assign('isAdminPage', false);
-$tmpl->assign('mounts', $mounts);
-$tmpl->assign('dependencies', OC_Mount_Config::checkDependencies());
+$tmpl->assign('storages', $userStoragesService->getAllStorages());
+$tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends()));
$tmpl->assign('backends', $backends);
+$tmpl->assign('authMechanisms', $authMechanisms);
return $tmpl->fetchPage();
diff --git a/apps/files_external/service/backendservice.php b/apps/files_external/service/backendservice.php
new file mode 100644
index 00000000000..bee08ecbd15
--- /dev/null
+++ b/apps/files_external/service/backendservice.php
@@ -0,0 +1,275 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Service;
+
+use \OCP\IConfig;
+
+use \OCA\Files_External\Lib\Backend\Backend;
+use \OCA\Files_External\Lib\Auth\AuthMechanism;
+
+/**
+ * Service class to manage backend definitions
+ */
+class BackendService {
+
+ /** Visibility constants for VisibilityTrait */
+ const VISIBILITY_NONE = 0;
+ const VISIBILITY_PERSONAL = 1;
+ const VISIBILITY_ADMIN = 2;
+ //const VISIBILITY_ALIENS = 4;
+
+ const VISIBILITY_DEFAULT = 3; // PERSONAL | ADMIN
+
+ /** Priority constants for PriorityTrait */
+ const PRIORITY_DEFAULT = 100;
+
+ /** @var IConfig */
+ protected $config;
+
+ /** @var bool */
+ private $userMountingAllowed = true;
+
+ /** @var string[] */
+ private $userMountingBackends = [];
+
+ /** @var Backend[] */
+ private $backends = [];
+
+ /** @var AuthMechanism[] */
+ private $authMechanisms = [];
+
+ /**
+ * @param IConfig $config
+ */
+ public function __construct(
+ IConfig $config
+ ) {
+ $this->config = $config;
+
+ // Load config values
+ if ($this->config->getAppValue('files_external', 'allow_user_mounting', 'yes') !== 'yes') {
+ $this->userMountingAllowed = false;
+ }
+ $this->userMountingBackends = explode(',',
+ $this->config->getAppValue('files_external', 'user_mounting_backends', '')
+ );
+ }
+
+ /**
+ * Register a backend
+ *
+ * @param Backend $backend
+ */
+ public function registerBackend(Backend $backend) {
+ if (!$this->isAllowedUserBackend($backend)) {
+ $backend->removeVisibility(BackendService::VISIBILITY_PERSONAL);
+ }
+ foreach ($backend->getIdentifierAliases() as $alias) {
+ $this->backends[$alias] = $backend;
+ }
+ }
+
+ /**
+ * @param Backend[] $backends
+ */
+ public function registerBackends(array $backends) {
+ foreach ($backends as $backend) {
+ $this->registerBackend($backend);
+ }
+ }
+ /**
+ * Register an authentication mechanism
+ *
+ * @param AuthMechanism $authMech
+ */
+ public function registerAuthMechanism(AuthMechanism $authMech) {
+ if (!$this->isAllowedAuthMechanism($authMech)) {
+ $authMech->removeVisibility(BackendService::VISIBILITY_PERSONAL);
+ }
+ foreach ($authMech->getIdentifierAliases() as $alias) {
+ $this->authMechanisms[$alias] = $authMech;
+ }
+ }
+
+ /**
+ * @param AuthMechanism[] $mechanisms
+ */
+ public function registerAuthMechanisms(array $mechanisms) {
+ foreach ($mechanisms as $mechanism) {
+ $this->registerAuthMechanism($mechanism);
+ }
+ }
+
+ /**
+ * Get all backends
+ *
+ * @return Backend[]
+ */
+ public function getBackends() {
+ // only return real identifiers, no aliases
+ $backends = [];
+ foreach ($this->backends as $backend) {
+ $backends[$backend->getIdentifier()] = $backend;
+ }
+ return $backends;
+ }
+
+ /**
+ * Get all available backends
+ *
+ * @return Backend[]
+ */
+ public function getAvailableBackends() {
+ return array_filter($this->getBackends(), function($backend) {
+ return empty($backend->checkDependencies());
+ });
+ }
+
+ /**
+ * Get backends visible for $visibleFor
+ *
+ * @param int $visibleFor
+ * @return Backend[]
+ */
+ public function getBackendsVisibleFor($visibleFor) {
+ return array_filter($this->getAvailableBackends(), function($backend) use ($visibleFor) {
+ return $backend->isVisibleFor($visibleFor);
+ });
+ }
+
+ /**
+ * Get backends allowed to be visible for $visibleFor
+ *
+ * @param int $visibleFor
+ * @return Backend[]
+ */
+ public function getBackendsAllowedVisibleFor($visibleFor) {
+ return array_filter($this->getAvailableBackends(), function($backend) use ($visibleFor) {
+ return $backend->isAllowedVisibleFor($visibleFor);
+ });
+ }
+
+ /**
+ * @param string $identifier
+ * @return Backend|null
+ */
+ public function getBackend($identifier) {
+ if (isset($this->backends[$identifier])) {
+ return $this->backends[$identifier];
+ }
+ return null;
+ }
+
+ /**
+ * Get all authentication mechanisms
+ *
+ * @return AuthMechanism[]
+ */
+ public function getAuthMechanisms() {
+ // only return real identifiers, no aliases
+ $mechanisms = [];
+ foreach ($this->authMechanisms as $mechanism) {
+ $mechanisms[$mechanism->getIdentifier()] = $mechanism;
+ }
+ return $mechanisms;
+ }
+
+ /**
+ * Get all authentication mechanisms for schemes
+ *
+ * @param string[] $schemes
+ * @return AuthMechanism[]
+ */
+ public function getAuthMechanismsByScheme(array $schemes) {
+ return array_filter($this->getAuthMechanisms(), function($authMech) use ($schemes) {
+ return in_array($authMech->getScheme(), $schemes, true);
+ });
+ }
+
+ /**
+ * Get authentication mechanisms visible for $visibleFor
+ *
+ * @param int $visibleFor
+ * @return AuthMechanism[]
+ */
+ public function getAuthMechanismsVisibleFor($visibleFor) {
+ return array_filter($this->getAuthMechanisms(), function($authMechanism) use ($visibleFor) {
+ return $authMechanism->isVisibleFor($visibleFor);
+ });
+ }
+
+ /**
+ * Get authentication mechanisms allowed to be visible for $visibleFor
+ *
+ * @param int $visibleFor
+ * @return AuthMechanism[]
+ */
+ public function getAuthMechanismsAllowedVisibleFor($visibleFor) {
+ return array_filter($this->getAuthMechanisms(), function($authMechanism) use ($visibleFor) {
+ return $authMechanism->isAllowedVisibleFor($visibleFor);
+ });
+ }
+
+
+ /**
+ * @param string $identifier
+ * @return AuthMechanism|null
+ */
+ public function getAuthMechanism($identifier) {
+ if (isset($this->authMechanisms[$identifier])) {
+ return $this->authMechanisms[$identifier];
+ }
+ return null;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isUserMountingAllowed() {
+ return $this->userMountingAllowed;
+ }
+
+ /**
+ * Check a backend if a user is allowed to mount it
+ *
+ * @param Backend $backend
+ * @return bool
+ */
+ protected function isAllowedUserBackend(Backend $backend) {
+ if ($this->userMountingAllowed &&
+ !empty(array_intersect($backend->getIdentifierAliases(), $this->userMountingBackends))
+ ) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Check an authentication mechanism if a user is allowed to use it
+ *
+ * @param AuthMechanism $authMechanism
+ * @return bool
+ */
+ protected function isAllowedAuthMechanism(AuthMechanism $authMechanism) {
+ return true; // not implemented
+ }
+}
diff --git a/apps/files_external/service/globalstoragesservice.php b/apps/files_external/service/globalstoragesservice.php
index 04445127b34..0e2d3f2b9c1 100644
--- a/apps/files_external/service/globalstoragesservice.php
+++ b/apps/files_external/service/globalstoragesservice.php
@@ -92,7 +92,7 @@ class GlobalStoragesService extends StoragesService {
$storageConfig->setBackendOptions($oldBackendOptions);
}
- \OC_Mount_Config::writeData(null, $mountPoints);
+ $this->writeLegacyConfig($mountPoints);
}
/**
diff --git a/apps/files_external/service/storagesservice.php b/apps/files_external/service/storagesservice.php
index 930f994455e..e89af6bc756 100644
--- a/apps/files_external/service/storagesservice.php
+++ b/apps/files_external/service/storagesservice.php
@@ -28,12 +28,23 @@ use \OC\Files\Filesystem;
use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_external\NotFoundException;
+use \OCA\Files_External\Service\BackendService;
/**
* Service class to manage external storages
*/
abstract class StoragesService {
+ /** @var BackendService */
+ protected $backendService;
+
+ /**
+ * @param BackendService $backendService
+ */
+ public function __construct(BackendService $backendService) {
+ $this->backendService = $backendService;
+ }
+
/**
* Read legacy config data
*
@@ -45,6 +56,16 @@ abstract class StoragesService {
}
/**
+ * Write legacy config data
+ *
+ * @param array $mountPoints
+ */
+ protected function writeLegacyConfig(array $mountPoints) {
+ // write global config
+ \OC_Mount_Config::writeData(null, $mountPoints);
+ }
+
+ /**
* Copy legacy storage options into the given storage config object.
*
* @param StorageConfig $storageConfig storage config to populate
@@ -60,14 +81,31 @@ abstract class StoragesService {
$applicable,
$storageOptions
) {
- $storageConfig->setBackendClass($storageOptions['class']);
+ $backend = $this->backendService->getBackend($storageOptions['backend']);
+ if (!$backend) {
+ throw new \UnexpectedValueException('Invalid backend '.$storageOptions['backend']);
+ }
+ $storageConfig->setBackend($backend);
+
+ if (isset($storageOptions['authMechanism'])) {
+ $authMechanism = $this->backendService->getAuthMechanism($storageOptions['authMechanism']);
+ } else {
+ $authMechanism = $backend->getLegacyAuthMechanism($storageOptions);
+ $storageOptions['authMechanism'] = 'null'; // to make error handling easier
+ }
+ if (!$authMechanism) {
+ throw new \UnexpectedValueException('Invalid authentication mechanism '.$storageOptions['authMechanism']);
+ }
+ $storageConfig->setAuthMechanism($authMechanism);
+
$storageConfig->setBackendOptions($storageOptions['options']);
if (isset($storageOptions['mountOptions'])) {
$storageConfig->setMountOptions($storageOptions['mountOptions']);
}
- if (isset($storageOptions['priority'])) {
- $storageConfig->setPriority($storageOptions['priority']);
+ if (!isset($storageOptions['priority'])) {
+ $storageOptions['priority'] = $backend->getPriority();
}
+ $storageConfig->setPriority($storageOptions['priority']);
if ($mountType === \OC_Mount_Config::MOUNT_TYPE_USER) {
$applicableUsers = $storageConfig->getApplicableUsers();
@@ -102,8 +140,10 @@ abstract class StoragesService {
* - $mountPath is the mount point path (where the storage must be mounted)
* - $storageOptions is a map of storage options:
* - "priority": storage priority
- * - "backend": backend class name
+ * - "backend": backend identifier
+ * - "class": LEGACY backend class name
* - "options": backend-specific options
+ * - "authMechanism": authentication mechanism identifier
* - "mountOptions": mount-specific options (ex: disable previews, scanner, etc)
*/
@@ -147,6 +187,13 @@ abstract class StoragesService {
// options might be needed for the config hash
$storageOptions['options'] = \OC_Mount_Config::decryptPasswords($storageOptions['options']);
+ if (!isset($storageOptions['backend'])) {
+ $storageOptions['backend'] = $storageOptions['class']; // legacy compat
+ }
+ if (!isset($storageOptions['authMechanism'])) {
+ $storageOptions['authMechanism'] = null; // ensure config hash works
+ }
+
if (isset($storageOptions['id'])) {
$configId = (int)$storageOptions['id'];
if (isset($storages[$configId])) {
@@ -188,21 +235,31 @@ abstract class StoragesService {
// process storages with config hash, they must get a real id
if (!empty($storagesWithConfigHash)) {
- $nextId = $this->generateNextId($storages);
- foreach ($storagesWithConfigHash as $storage) {
- $storage->setId($nextId);
- $storages[$nextId] = $storage;
- $nextId++;
- }
-
- // re-save the config with the generated ids
- $this->writeConfig($storages);
+ $this->setRealStorageIds($storages, $storagesWithConfigHash);
}
return $storages;
}
/**
+ * Replace config hash ID with real IDs, for migrating legacy storages
+ *
+ * @param StorageConfig[] $storages Storages with real IDs
+ * @param StorageConfig[] $storagesWithConfigHash Storages with config hash IDs
+ */
+ protected function setRealStorageIds(array &$storages, array $storagesWithConfigHash) {
+ $nextId = $this->generateNextId($storages);
+ foreach ($storagesWithConfigHash as $storage) {
+ $storage->setId($nextId);
+ $storages[$nextId] = $storage;
+ $nextId++;
+ }
+
+ // re-save the config with the generated ids
+ $this->writeConfig($storages);
+ }
+
+ /**
* Add mount point into the messy mount point structure
*
* @param array $mountPoints messy array of mount points
@@ -222,7 +279,9 @@ abstract class StoragesService {
$options = [
'id' => $storageConfig->getId(),
- 'class' => $storageConfig->getBackendClass(),
+ 'backend' => $storageConfig->getBackend()->getIdentifier(),
+ //'class' => $storageConfig->getBackend()->getClass(),
+ 'authMechanism' => $storageConfig->getAuthMechanism()->getIdentifier(),
'options' => $storageConfig->getBackendOptions(),
];
@@ -297,6 +356,59 @@ abstract class StoragesService {
}
/**
+ * Create a storage from its parameters
+ *
+ * @param string $mountPoint storage mount point
+ * @param string $backendIdentifier backend identifier
+ * @param string $authMechanismIdentifier authentication mechanism identifier
+ * @param array $backendOptions backend-specific options
+ * @param array|null $mountOptions mount-specific options
+ * @param array|null $applicableUsers users for which to mount the storage
+ * @param array|null $applicableGroups groups for which to mount the storage
+ * @param int|null $priority priority
+ *
+ * @return StorageConfig
+ */
+ public function createStorage(
+ $mountPoint,
+ $backendIdentifier,
+ $authMechanismIdentifier,
+ $backendOptions,
+ $mountOptions = null,
+ $applicableUsers = null,
+ $applicableGroups = null,
+ $priority = null
+ ) {
+ $backend = $this->backendService->getBackend($backendIdentifier);
+ if (!$backend) {
+ throw new \InvalidArgumentException('Unable to get backend for '.$backendIdentifier);
+ }
+ $authMechanism = $this->backendService->getAuthMechanism($authMechanismIdentifier);
+ if (!$authMechanism) {
+ throw new \InvalidArgumentException('Unable to get authentication mechanism for '.$authMechanismIdentifier);
+ }
+ $newStorage = new StorageConfig();
+ $newStorage->setMountPoint($mountPoint);
+ $newStorage->setBackend($backend);
+ $newStorage->setAuthMechanism($authMechanism);
+ $newStorage->setBackendOptions($backendOptions);
+ if (isset($mountOptions)) {
+ $newStorage->setMountOptions($mountOptions);
+ }
+ if (isset($applicableUsers)) {
+ $newStorage->setApplicableUsers($applicableUsers);
+ }
+ if (isset($applicableGroups)) {
+ $newStorage->setApplicableGroups($applicableGroups);
+ }
+ if (isset($priority)) {
+ $newStorage->setPriority($priority);
+ }
+
+ return $newStorage;
+ }
+
+ /**
* Triggers the given hook signal for all the applicables given
*
* @param string $signal signal
diff --git a/apps/files_external/service/userglobalstoragesservice.php b/apps/files_external/service/userglobalstoragesservice.php
new file mode 100644
index 00000000000..78520419556
--- /dev/null
+++ b/apps/files_external/service/userglobalstoragesservice.php
@@ -0,0 +1,107 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Service;
+
+use \OCA\Files_external\Service\GlobalStoragesService;
+use \OCA\Files_External\Service\BackendService;
+use \OCP\IUserSession;
+use \OCP\IGroupManager;
+use \OCA\Files_External\Service\UserTrait;
+
+/**
+ * Service class to read global storages applicable to the user
+ * Read-only access available, attempting to write will throw DomainException
+ */
+class UserGlobalStoragesService extends GlobalStoragesService {
+
+ use UserTrait;
+
+ /** @var IGroupManager */
+ protected $groupManager;
+
+ /**
+ * @param BackendService $backendService
+ * @param IUserSession $userSession
+ * @param IGroupManager $groupManager
+ */
+ public function __construct(
+ BackendService $backendService,
+ IUserSession $userSession,
+ IGroupManager $groupManager
+ ) {
+ parent::__construct($backendService);
+ $this->userSession = $userSession;
+ $this->groupManager = $groupManager;
+ }
+
+ /**
+ * Replace config hash ID with real IDs, for migrating legacy storages
+ *
+ * @param StorageConfig[] $storages Storages with real IDs
+ * @param StorageConfig[] $storagesWithConfigHash Storages with config hash IDs
+ */
+ protected function setRealStorageIds(array &$storages, array $storagesWithConfigHash) {
+ // as a read-only view, storage IDs don't need to be real
+ foreach ($storagesWithConfigHash as $storage) {
+ $storages[$storage->getId()] = $storage;
+ }
+ }
+
+ /**
+ * Read legacy config data
+ *
+ * @return array list of mount configs
+ */
+ protected function readLegacyConfig() {
+ // read global config
+ $data = parent::readLegacyConfig();
+ $userId = $this->getUser()->getUID();
+
+ if (isset($data[\OC_Mount_Config::MOUNT_TYPE_USER])) {
+ $data[\OC_Mount_Config::MOUNT_TYPE_USER] = array_filter(
+ $data[\OC_Mount_Config::MOUNT_TYPE_USER], function($key) use ($userId) {
+ return (strtolower($key) === strtolower($userId) || $key === 'all');
+ }, ARRAY_FILTER_USE_KEY
+ );
+ }
+
+ if (isset($data[\OC_Mount_Config::MOUNT_TYPE_GROUP])) {
+ $data[\OC_Mount_Config::MOUNT_TYPE_GROUP] = array_filter(
+ $data[\OC_Mount_Config::MOUNT_TYPE_GROUP], function($key) use ($userId) {
+ return ($this->groupManager->isInGroup($userId, $key));
+ }, ARRAY_FILTER_USE_KEY
+ );
+ }
+
+ return $data;
+ }
+
+ /**
+ * Write legacy config data
+ *
+ * @param array $mountPoints
+ */
+ protected function writeLegacyConfig(array $mountPoints) {
+ throw new \DomainException('UserGlobalStoragesService writing disallowed');
+ }
+
+}
diff --git a/apps/files_external/service/userstoragesservice.php b/apps/files_external/service/userstoragesservice.php
index 2f2556043fe..c69b8d4f51e 100644
--- a/apps/files_external/service/userstoragesservice.php
+++ b/apps/files_external/service/userstoragesservice.php
@@ -26,6 +26,8 @@ use \OC\Files\Filesystem;
use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_external\NotFoundException;
+use \OCA\Files_External\Service\BackendService;
+use \OCA\Files_External\Service\UserTrait;
/**
* Service class to manage user external storages
@@ -33,22 +35,20 @@ use \OCA\Files_external\NotFoundException;
*/
class UserStoragesService extends StoragesService {
- /**
- * User session
- *
- * @var IUserSession
- */
- private $userSession;
+ use UserTrait;
/**
* Create a user storages service
*
+ * @param BackendService $backendService
* @param IUserSession $userSession user session
*/
public function __construct(
+ BackendService $backendService,
IUserSession $userSession
) {
$this->userSession = $userSession;
+ parent::__construct($backendService);
}
/**
@@ -58,17 +58,28 @@ class UserStoragesService extends StoragesService {
*/
protected function readLegacyConfig() {
// read user config
- $user = $this->userSession->getUser()->getUID();
+ $user = $this->getUser()->getUID();
return \OC_Mount_Config::readData($user);
}
/**
+ * Write legacy config data
+ *
+ * @param array $mountPoints
+ */
+ protected function writeLegacyConfig(array $mountPoints) {
+ // write user config
+ $user = $this->getUser()->getUID();
+ \OC_Mount_Config::writeData($user, $mountPoints);
+ }
+
+ /**
* Read the external storages config
*
* @return array map of storage id to storage config
*/
protected function readConfig() {
- $user = $this->userSession->getUser()->getUID();
+ $user = $this->getUser()->getUID();
// TODO: in the future don't rely on the global config reading code
$storages = parent::readConfig();
@@ -95,7 +106,7 @@ class UserStoragesService extends StoragesService {
* @param array $storages map of storage id to storage config
*/
public function writeConfig($storages) {
- $user = $this->userSession->getUser()->getUID();
+ $user = $this->getUser()->getUID();
// let the horror begin
$mountPoints = [];
@@ -123,7 +134,7 @@ class UserStoragesService extends StoragesService {
$storageConfig->setBackendOptions($oldBackendOptions);
}
- \OC_Mount_Config::writeData($user, $mountPoints);
+ $this->writeLegacyConfig($mountPoints);
}
/**
@@ -134,7 +145,7 @@ class UserStoragesService extends StoragesService {
* @param string $signal signal to trigger
*/
protected function triggerHooks(StorageConfig $storage, $signal) {
- $user = $this->userSession->getUser()->getUID();
+ $user = $this->getUser()->getUID();
// trigger hook for the current user
$this->triggerApplicableHooks(
diff --git a/apps/files_external/service/usertrait.php b/apps/files_external/service/usertrait.php
new file mode 100644
index 00000000000..4f84543565c
--- /dev/null
+++ b/apps/files_external/service/usertrait.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Service;
+
+use \OCP\IUserSession;
+use \OCP\IUser;
+
+/**
+ * Trait for getting user information in a service
+ */
+trait UserTrait {
+
+ /** @var IUserSession */
+ protected $userSession;
+
+ /**
+ * User override
+ *
+ * @var IUser|null
+ */
+ private $user = null;
+
+ /**
+ * @return IUser|null
+ */
+ protected function getUser() {
+ if ($this->user) {
+ return $this->user;
+ }
+ return $this->userSession->getUser();
+ }
+
+ /**
+ * Override the user from the session
+ * Unset with ->resetUser() when finished!
+ *
+ * @param IUser
+ * @return self
+ */
+ public function setUser(IUser $user) {
+ $this->user = $user;
+ return $this;
+ }
+
+ /**
+ * Reset the user override
+ *
+ * @return self
+ */
+ public function resetUser() {
+ $this->user = null;
+ return $this;
+ }
+}
+
diff --git a/apps/files_external/settings.php b/apps/files_external/settings.php
index 6db68713d98..9cecc0c6a49 100644
--- a/apps/files_external/settings.php
+++ b/apps/files_external/settings.php
@@ -26,54 +26,41 @@
*
*/
+use \OCA\Files_External\Service\BackendService;
+
OC_Util::checkAdminUser();
+// we must use the same container
+$appContainer = \OC_Mount_Config::$app->getContainer();
+$backendService = $appContainer->query('OCA\Files_External\Service\BackendService');
+$globalStoragesService = $appContainer->query('OCA\Files_external\Service\GlobalStoragesService');
+
OCP\Util::addScript('files_external', 'settings');
OCP\Util::addStyle('files_external', 'settings');
\OC_Util::addVendorScript('select2/select2');
\OC_Util::addVendorStyle('select2/select2');
-$backends = OC_Mount_Config::getBackends();
-$personal_backends = array();
-$enabled_backends = explode(',', OCP\Config::getAppValue('files_external', 'user_mounting_backends', ''));
-foreach ($backends as $class => $backend)
-{
- if ($class != '\OC\Files\Storage\Local')
- {
- $personal_backends[$class] = array(
- 'backend' => $backend['backend'],
- 'enabled' => in_array($class, $enabled_backends),
- );
+$backends = $backendService->getBackendsVisibleFor(BackendService::VISIBILITY_ADMIN);
+$authMechanisms = $backendService->getAuthMechanismsVisibleFor(BackendService::VISIBILITY_ADMIN);
+foreach ($backends as $backend) {
+ if ($backend->getCustomJs()) {
+ \OCP\Util::addScript('files_external', $backend->getCustomJs());
}
}
-
-$mounts = OC_Mount_Config::getSystemMountPoints();
-$hasId = true;
-foreach ($mounts as $mount) {
- if (!isset($mount['id'])) {
- // some mount points are missing ids
- $hasId = false;
- break;
+foreach ($authMechanisms as $authMechanism) {
+ if ($authMechanism->getCustomJs()) {
+ \OCP\Util::addScript('files_external', $authMechanism->getCustomJs());
}
}
-if (!$hasId) {
- $service = new \OCA\Files_external\Service\GlobalStoragesService();
- // this will trigger the new storage code which will automatically
- // generate storage config ids
- $service->getAllStorages();
- // re-read updated config
- $mounts = OC_Mount_Config::getSystemMountPoints();
- // TODO: use the new storage config format in the template
-}
-
$tmpl = new OCP\Template('files_external', 'settings');
$tmpl->assign('encryptionEnabled', \OC::$server->getEncryptionManager()->isEnabled());
$tmpl->assign('isAdminPage', true);
-$tmpl->assign('mounts', $mounts);
+$tmpl->assign('storages', $globalStoragesService->getAllStorages());
$tmpl->assign('backends', $backends);
-$tmpl->assign('personal_backends', $personal_backends);
-$tmpl->assign('dependencies', OC_Mount_Config::checkDependencies());
-$tmpl->assign('allowUserMounting', OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes'));
+$tmpl->assign('authMechanisms', $authMechanisms);
+$tmpl->assign('userBackends', $backendService->getBackendsAllowedVisibleFor(BackendService::VISIBILITY_PERSONAL));
+$tmpl->assign('dependencies', OC_Mount_Config::dependencyMessage($backendService->getBackends()));
+$tmpl->assign('allowUserMounting', $backendService->isUserMountingAllowed());
return $tmpl->fetchPage();
diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php
index b886c2e1b1b..611c5807a5f 100644
--- a/apps/files_external/templates/settings.php
+++ b/apps/files_external/templates/settings.php
@@ -1,3 +1,58 @@
+<?php
+ use \OCA\Files_External\Lib\Backend\Backend;
+ use \OCA\Files_External\Lib\DefinitionParameter;
+ use \OCA\Files_External\Service\BackendService;
+
+ function writeParameterInput($parameter, $options, $classes = []) {
+ $value = '';
+ if (isset($options[$parameter->getName()])) {
+ $value = $options[$parameter->getName()];
+ }
+ $placeholder = $parameter->getText();
+ $is_optional = $parameter->isFlagSet(DefinitionParameter::FLAG_OPTIONAL);
+
+ switch ($parameter->getType()) {
+ case DefinitionParameter::VALUE_PASSWORD: ?>
+ <?php if ($is_optional) { $classes[] = 'optional'; } ?>
+ <input type="password"
+ <?php if (!empty($classes)): ?> class="<?php p(implode(' ', $classes)); ?>"<?php endif; ?>
+ data-parameter="<?php p($parameter->getName()); ?>"
+ value="<?php p($value); ?>"
+ placeholder="<?php p($placeholder); ?>"
+ />
+ <?php
+ break;
+ case DefinitionParameter::VALUE_BOOLEAN: ?>
+ <label>
+ <input type="checkbox"
+ <?php if (!empty($classes)): ?> class="<?php p(implode(' ', $classes)); ?>"<?php endif; ?>
+ data-parameter="<?php p($parameter->getName()); ?>"
+ <?php if ($value == 'true'): ?> checked="checked"<?php endif; ?>
+ />
+ <?php p($placeholder); ?>
+ </label>
+ <?php
+ break;
+ case DefinitionParameter::VALUE_HIDDEN: ?>
+ <input type="hidden"
+ <?php if (!empty($classes)): ?> class="<?php p(implode(' ', $classes)); ?>"<?php endif; ?>
+ data-parameter="<?php p($parameter->getName()); ?>"
+ value="<?php p($value); ?>"
+ />
+ <?php
+ break;
+ default: ?>
+ <?php if ($is_optional) { $classes[] = 'optional'; } ?>
+ <input type="text"
+ <?php if (!empty($classes)): ?> class="<?php p(implode(' ', $classes)); ?>"<?php endif; ?>
+ data-parameter="<?php p($parameter->getName()); ?>"
+ value="<?php p($value); ?>"
+ placeholder="<?php p($placeholder); ?>"
+ />
+ <?php
+ }
+ }
+?>
<form id="files_external" class="section" data-encryption-enabled="<?php echo $_['encryptionEnabled']?'true': 'false'; ?>">
<h2><?php p($l->t('External Storage')); ?></h2>
<?php if (isset($_['dependencies']) and ($_['dependencies']<>'')) print_unescaped(''.$_['dependencies'].''); ?>
@@ -7,6 +62,7 @@
<th></th>
<th><?php p($l->t('Folder name')); ?></th>
<th><?php p($l->t('External storage')); ?></th>
+ <th><?php p($l->t('Authentication')); ?></th>
<th><?php p($l->t('Configuration')); ?></th>
<?php if ($_['isAdminPage']) print_unescaped('<th>'.$l->t('Available for').'</th>'); ?>
<th>&nbsp;</th>
@@ -14,103 +70,120 @@
</tr>
</thead>
<tbody>
- <?php $_['mounts'] = array_merge($_['mounts'], array('' => array('id' => ''))); ?>
- <?php foreach ($_['mounts'] as $mount): ?>
- <tr <?php print_unescaped(isset($mount['mountpoint']) ? 'class="'.OC_Util::sanitizeHTML($mount['class']).'"' : 'id="addMountPoint"'); ?> data-id="<?php p($mount['id']) ?>">
+ <?php foreach ($_['storages'] as $storage): ?>
+ <tr class="<?php p($storage->getBackend()->getIdentifier()); ?>" data-id="<?php p($storage->getId()); ?>">
<td class="status">
<span></span>
</td>
<td class="mountPoint"><input type="text" name="mountPoint"
- value="<?php p(isset($mount['mountpoint']) ? $mount['mountpoint'] : ''); ?>"
- data-mountpoint="<?php p(isset($mount['mountpoint']) ? $mount['mountpoint'] : ''); ?>"
+ value="<?php p(ltrim($storage->getMountPoint(), '/')); ?>"
+ data-mountpoint="<?php p(ltrim($storage->getMountPoint(), '/')); ?>"
placeholder="<?php p($l->t('Folder name')); ?>" />
</td>
- <?php if (!isset($mount['mountpoint'])): ?>
- <td class="backend">
- <select id="selectBackend" class="selectBackend" data-configurations='<?php p(json_encode($_['backends'])); ?>'>
- <option value="" disabled selected
- style="display:none;"><?php p($l->t('Add storage')); ?></option>
- <?php foreach ($_['backends'] as $class => $backend): ?>
- <option value="<?php p($class); ?>"><?php p($backend['backend']); ?></option>
- <?php endforeach; ?>
- </select>
- </td>
- <?php else: ?>
- <td class="backend" data-class="<?php p($mount['class']); ?>"><?php p($mount['backend']); ?>
- </td>
- <?php endif; ?>
- <td class ="configuration">
- <?php if (isset($mount['options'])): ?>
- <?php foreach ($mount['options'] as $parameter => $value): ?>
- <?php if (isset($_['backends'][$mount['class']]['configuration'][$parameter])): ?>
- <?php
- $placeholder = $_['backends'][$mount['class']]['configuration'][$parameter];
- $is_optional = FALSE;
- if (strpos($placeholder, '&') === 0) {
- $is_optional = TRUE;
- $placeholder = substr($placeholder, 1);
- }
- ?>
- <?php if (strpos($placeholder, '*') === 0): ?>
- <input type="password"
- <?php if ($is_optional): ?> class="optional"<?php endif; ?>
- data-parameter="<?php p($parameter); ?>"
- value="<?php p($value); ?>"
- placeholder="<?php p(substr($placeholder, 1)); ?>" />
- <?php elseif (strpos($placeholder, '!') === 0): ?>
- <label><input type="checkbox"
- data-parameter="<?php p($parameter); ?>"
- <?php if ($value == 'true'): ?> checked="checked"<?php endif; ?>
- /><?php p(substr($placeholder, 1)); ?></label>
- <?php elseif (strpos($placeholder, '#') === 0): ?>
- <input type="hidden"
- data-parameter="<?php p($parameter); ?>"
- value="<?php p($value); ?>" />
- <?php else: ?>
- <input type="text"
- <?php if ($is_optional): ?> class="optional"<?php endif; ?>
- data-parameter="<?php p($parameter); ?>"
- value="<?php p($value); ?>"
- placeholder="<?php p($placeholder); ?>" />
- <?php endif; ?>
- <?php endif; ?>
+ <td class="backend" data-class="<?php p($storage->getBackend()->getIdentifier()); ?>"><?php p($storage->getBackend()->getText()); ?>
+ </td>
+ <td class="authentication">
+ <select class="selectAuthMechanism">
+ <?php
+ $authSchemes = $storage->getBackend()->getAuthSchemes();
+ $authMechanisms = array_filter($_['authMechanisms'], function($mech) use ($authSchemes) {
+ return isset($authSchemes[$mech->getScheme()]);
+ });
+ ?>
+ <?php foreach ($authMechanisms as $mech): ?>
+ <option value="<?php p($mech->getIdentifier()); ?>" data-scheme="<?php p($mech->getScheme());?>"
+ <?php if ($mech->getIdentifier() === $storage->getAuthMechanism()->getIdentifier()): ?>selected<?php endif; ?>
+ ><?php p($mech->getText()); ?></option>
<?php endforeach; ?>
- <?php if (isset($_['backends'][$mount['class']]['custom'])): ?>
- <?php OCP\Util::addScript('files_external', $_['backends'][$mount['class']]['custom']); ?>
- <?php endif; ?>
- <?php endif; ?>
+ </select>
</td>
- <?php if ($_['isAdminPage']): ?>
- <td class="applicable"
- align="right"
- data-applicable-groups='<?php if (isset($mount['applicable']['groups']))
- print_unescaped(json_encode($mount['applicable']['groups'])); ?>'
- data-applicable-users='<?php if (isset($mount['applicable']['users']))
- print_unescaped(json_encode($mount['applicable']['users'])); ?>'>
- <input type="hidden" class="applicableUsers" style="width:20em;" value=""/>
+ <td class="configuration">
+ <?php
+ $options = $storage->getBackendOptions();
+ foreach ($storage->getBackend()->getParameters() as $parameter) {
+ writeParameterInput($parameter, $options);
+ }
+ foreach ($storage->getAuthMechanism()->getParameters() as $parameter) {
+ writeParameterInput($parameter, $options, ['auth-param']);
+ }
+ ?>
</td>
+ <?php if ($_['isAdminPage']): ?>
+ <td class="applicable"
+ align="right"
+ data-applicable-groups='<?php print_unescaped(json_encode($storage->getApplicableGroups())); ?>'
+ data-applicable-users='<?php print_unescaped(json_encode($storage->getApplicableUsers())); ?>'>
+ <input type="hidden" class="applicableUsers" style="width:20em;" value=""/>
+ </td>
<?php endif; ?>
- <td class="mountOptionsToggle <?php if (!isset($mount['mountpoint'])) { p('hidden'); } ?>"
- ><img
+ <td class="mountOptionsToggle">
+ <img
class="svg action"
title="<?php p($l->t('Advanced settings')); ?>"
alt="<?php p($l->t('Advanced settings')); ?>"
- src="<?php print_unescaped(image_path('core', 'actions/settings.svg')); ?>" />
- <input type="hidden" class="mountOptions" value="<?php isset($mount['mountOptions']) ? p(json_encode($mount['mountOptions'])) : '' ?>" />
+ src="<?php print_unescaped(image_path('core', 'actions/settings.svg')); ?>"
+ />
+ <input type="hidden" class="mountOptions" value="<?php p(json_encode($storage->getMountOptions())); ?>" />
<?php if ($_['isAdminPage']): ?>
- <?php if (isset($mount['priority'])): ?>
- <input type="hidden" class="priority" value="<?php p($mount['priority']) ?>" />
- <?php endif; ?>
+ <input type="hidden" class="priority" value="<?php p($storage->getPriority()); ?>" />
<?php endif; ?>
</td>
- <td <?php if (isset($mount['mountpoint'])): ?>class="remove"
- <?php else: ?>class="hidden"
- <?php endif ?>><img alt="<?php p($l->t('Delete')); ?>"
- title="<?php p($l->t('Delete')); ?>"
- class="svg action"
- src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>" /></td>
+ <td class="remove">
+ <img alt="<?php p($l->t('Delete')); ?>"
+ title="<?php p($l->t('Delete')); ?>"
+ class="svg action"
+ src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>"
+ />
+ </td>
</tr>
<?php endforeach; ?>
+ <tr id="addMountPoint">
+ <td class="status">
+ <span></span>
+ </td>
+ <td class="mountPoint"><input type="text" name="mountPoint" value=""
+ placeholder="<?php p($l->t('Folder name')); ?>">
+ </td>
+ <td class="backend">
+ <select id="selectBackend" class="selectBackend" data-configurations='<?php p(json_encode($_['backends'])); ?>'>
+ <option value="" disabled selected
+ style="display:none;">
+ <?php p($l->t('Add storage')); ?>
+ </option>
+ <?php
+ $sortedBackends = $_['backends'];
+ uasort($sortedBackends, function($a, $b) {
+ return strcasecmp($a->getText(), $b->getText());
+ });
+ ?>
+ <?php foreach ($sortedBackends as $backend): ?>
+ <option value="<?php p($backend->getIdentifier()); ?>"><?php p($backend->getText()); ?></option>
+ <?php endforeach; ?>
+ </select>
+ </td>
+ <td class="authentication" data-mechanisms='<?php p(json_encode($_['authMechanisms'])); ?>'></td>
+ <td class="configuration"></td>
+ <?php if ($_['isAdminPage']): ?>
+ <td class="applicable" align="right">
+ <input type="hidden" class="applicableUsers" style="width:20em;" value="" />
+ </td>
+ <?php endif; ?>
+ <td class="mountOptionsToggle hidden">
+ <img class="svg action"
+ title="<?php p($l->t('Advanced settings')); ?>"
+ alt="<?php p($l->t('Advanced settings')); ?>"
+ src="<?php print_unescaped(image_path('core', 'actions/settings.svg')); ?>"
+ />
+ <input type="hidden" class="mountOptions" value="" />
+ </td>
+ <td class="hidden">
+ <img class="svg action"
+ alt="<?php p($l->t('Delete')); ?>"
+ title="<?php p($l->t('Delete')); ?>"
+ src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>"
+ />
+ </td>
+ </tr>
</tbody>
</table>
<br />
@@ -123,9 +196,9 @@
<p id="userMountingBackends"<?php if ($_['allowUserMounting'] != 'yes'): ?> class="hidden"<?php endif; ?>>
<?php p($l->t('Allow users to mount the following external storage')); ?><br />
- <?php $i = 0; foreach ($_['personal_backends'] as $class => $backend): ?>
- <input type="checkbox" id="allowUserMountingBackends<?php p($i); ?>" name="allowUserMountingBackends[]" value="<?php p($class); ?>" <?php if ($backend['enabled']) print_unescaped(' checked="checked"'); ?> />
- <label for="allowUserMountingBackends<?php p($i); ?>"><?php p($backend['backend']); ?></label> <br />
+ <?php $i = 0; foreach ($_['userBackends'] as $backend): ?>
+ <input type="checkbox" id="allowUserMountingBackends<?php p($i); ?>" name="allowUserMountingBackends[]" value="<?php p($backend->getIdentifier()); ?>" <?php if ($backend->isVisibleFor(BackendService::VISIBILITY_PERSONAL)) print_unescaped(' checked="checked"'); ?> />
+ <label for="allowUserMountingBackends<?php p($i); ?>"><?php p($backend->getText()); ?></label> <br />
<?php $i++; ?>
<?php endforeach; ?>
</p>
diff --git a/apps/files_external/tests/auth/authmechanismtest.php b/apps/files_external/tests/auth/authmechanismtest.php
new file mode 100644
index 00000000000..b09d65a02df
--- /dev/null
+++ b/apps/files_external/tests/auth/authmechanismtest.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Tests\Auth;
+
+class AuthMechanismTest extends \Test\TestCase {
+
+ public function testJsonSerialization() {
+ $mechanism = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism')
+ ->setMethods(['jsonSerializeDefinition'])
+ ->getMock();
+ $mechanism->expects($this->once())
+ ->method('jsonSerializeDefinition')
+ ->willReturn(['foo' => 'bar']);
+
+ $mechanism->setScheme('scheme');
+
+ $json = $mechanism->jsonSerialize();
+ $this->assertEquals('bar', $json['foo']);
+ $this->assertEquals('scheme', $json['scheme']);
+ }
+
+ public function validateStorageProvider() {
+ return [
+ [true, 'scheme', true],
+ [false, 'scheme', false],
+ [true, 'foobar', true],
+ [false, 'barfoo', true],
+ ];
+ }
+
+ /**
+ * @dataProvider validateStorageProvider
+ */
+ public function testValidateStorage($expectedSuccess, $scheme, $definitionSuccess) {
+ $mechanism = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism')
+ ->setMethods(['validateStorageDefinition'])
+ ->getMock();
+ $mechanism->expects($this->atMost(1))
+ ->method('validateStorageDefinition')
+ ->willReturn($definitionSuccess);
+
+ $mechanism->setScheme($scheme);
+
+ $backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $backend->expects($this->once())
+ ->method('getAuthSchemes')
+ ->willReturn(['scheme' => true, 'foobar' => true]);
+
+ $storageConfig = $this->getMockBuilder('\OCA\Files_External\Lib\StorageConfig')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $storageConfig->expects($this->once())
+ ->method('getBackend')
+ ->willReturn($backend);
+
+ $this->assertEquals($expectedSuccess, $mechanism->validateStorage($storageConfig));
+ }
+
+}
diff --git a/apps/files_external/tests/backend/backendtest.php b/apps/files_external/tests/backend/backendtest.php
new file mode 100644
index 00000000000..4956a923e94
--- /dev/null
+++ b/apps/files_external/tests/backend/backendtest.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Tests\Backend;
+
+use \OCA\Files_External\Lib\Backend\Backend;
+
+class BackendTest extends \Test\TestCase {
+
+ public function testJsonSerialization() {
+ $backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
+ ->setMethods(['jsonSerializeDefinition'])
+ ->getMock();
+ $backend->expects($this->once())
+ ->method('jsonSerializeDefinition')
+ ->willReturn(['foo' => 'bar', 'name' => 'abc']);
+
+ $backend->setPriority(57);
+ $backend->addAuthScheme('foopass');
+ $backend->addAuthScheme('barauth');
+
+ $json = $backend->jsonSerialize();
+ $this->assertEquals('bar', $json['foo']);
+ $this->assertEquals('abc', $json['name']);
+ $this->assertEquals($json['name'], $json['backend']);
+ $this->assertEquals(57, $json['priority']);
+
+ $this->assertContains('foopass', $json['authSchemes']);
+ $this->assertContains('barauth', $json['authSchemes']);
+ }
+
+ public function validateStorageProvider() {
+ return [
+ [true, true],
+ [false, false],
+ ];
+ }
+
+ /**
+ * @dataProvider validateStorageProvider
+ */
+ public function testValidateStorage($expectedSuccess, $definitionSuccess) {
+ $backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
+ ->setMethods(['validateStorageDefinition'])
+ ->getMock();
+ $backend->expects($this->atMost(1))
+ ->method('validateStorageDefinition')
+ ->willReturn($definitionSuccess);
+
+ $storageConfig = $this->getMockBuilder('\OCA\Files_External\Lib\StorageConfig')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->assertEquals($expectedSuccess, $backend->validateStorage($storageConfig));
+ }
+
+ public function testLegacyAuthMechanismCallback() {
+ $backend = new Backend();
+ $backend->setLegacyAuthMechanismCallback(function(array $params) {
+ if (isset($params['ping'])) {
+ return 'pong';
+ }
+ return 'foobar';
+ });
+
+ $this->assertEquals('pong', $backend->getLegacyAuthMechanism(['ping' => true]));
+ $this->assertEquals('foobar', $backend->getLegacyAuthMechanism(['other' => true]));
+ $this->assertEquals('foobar', $backend->getLegacyAuthMechanism());
+ }
+
+}
diff --git a/apps/files_external/tests/backend/legacybackendtest.php b/apps/files_external/tests/backend/legacybackendtest.php
new file mode 100644
index 00000000000..44cb16a4986
--- /dev/null
+++ b/apps/files_external/tests/backend/legacybackendtest.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Tests\Backend;
+
+use \OCA\Files_External\Lib\Backend\LegacyBackend;
+use \OCA\Files_External\Lib\DefinitionParameter;
+
+class LegacyBackendTest extends \Test\TestCase {
+
+ public function testConstructor() {
+ $auth = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\Builtin')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $class = '\OC\Files\Storage\SMB';
+ $definition = [
+ 'configuration' => [
+ 'textfield' => 'Text field',
+ 'passwordfield' => '*Password field',
+ 'checkbox' => '!Checkbox',
+ 'hiddenfield' => '#Hidden field',
+ 'optionaltext' => '&Optional text field',
+ 'optionalpassword' => '&*Optional password field',
+ ],
+ 'backend' => 'Backend text',
+ 'priority' => 123,
+ 'custom' => 'foo/bar.js',
+ 'has_dependencies' => true,
+ ];
+
+ $backend = new LegacyBackend($class, $definition, $auth);
+
+ $this->assertEquals('\OC\Files\Storage\SMB', $backend->getStorageClass());
+ $this->assertEquals('Backend text', $backend->getText());
+ $this->assertEquals(123, $backend->getPriority());
+ $this->assertEquals('foo/bar.js', $backend->getCustomJs());
+ $this->assertEquals(true, $backend->hasDependencies());
+ $this->assertArrayHasKey('builtin', $backend->getAuthSchemes());
+ $this->assertEquals($auth, $backend->getLegacyAuthMechanism());
+
+ $parameters = $backend->getParameters();
+ $this->assertEquals('Text field', $parameters['textfield']->getText());
+ $this->assertEquals(DefinitionParameter::VALUE_TEXT, $parameters['textfield']->getType());
+ $this->assertEquals(DefinitionParameter::FLAG_NONE, $parameters['textfield']->getFlags());
+ $this->assertEquals('Password field', $parameters['passwordfield']->getText());
+ $this->assertEquals(DefinitionParameter::VALUE_PASSWORD, $parameters['passwordfield']->getType());
+ $this->assertEquals(DefinitionParameter::FLAG_NONE, $parameters['passwordfield']->getFlags());
+ $this->assertEquals('Checkbox', $parameters['checkbox']->getText());
+ $this->assertEquals(DefinitionParameter::VALUE_BOOLEAN, $parameters['checkbox']->getType());
+ $this->assertEquals(DefinitionParameter::FLAG_NONE, $parameters['checkbox']->getFlags());
+ $this->assertEquals('Hidden field', $parameters['hiddenfield']->getText());
+ $this->assertEquals(DefinitionParameter::VALUE_HIDDEN, $parameters['hiddenfield']->getType());
+ $this->assertEquals(DefinitionParameter::FLAG_NONE, $parameters['hiddenfield']->getFlags());
+ $this->assertEquals('Optional text field', $parameters['optionaltext']->getText());
+ $this->assertEquals(DefinitionParameter::VALUE_TEXT, $parameters['optionaltext']->getType());
+ $this->assertEquals(DefinitionParameter::FLAG_OPTIONAL, $parameters['optionaltext']->getFlags());
+ $this->assertEquals('Optional password field', $parameters['optionalpassword']->getText());
+ $this->assertEquals(DefinitionParameter::VALUE_PASSWORD, $parameters['optionalpassword']->getType());
+ $this->assertEquals(DefinitionParameter::FLAG_OPTIONAL, $parameters['optionalpassword']->getFlags());
+ }
+
+}
diff --git a/apps/files_external/tests/controller/globalstoragescontrollertest.php b/apps/files_external/tests/controller/globalstoragescontrollertest.php
index fc58743454a..e1bfad8caf6 100644
--- a/apps/files_external/tests/controller/globalstoragescontrollertest.php
+++ b/apps/files_external/tests/controller/globalstoragescontrollertest.php
@@ -28,7 +28,9 @@ use \OCA\Files_external\NotFoundException;
class GlobalStoragesControllerTest extends StoragesControllerTest {
public function setUp() {
parent::setUp();
- $this->service = $this->getMock('\OCA\Files_external\Service\GlobalStoragesService');
+ $this->service = $this->getMockBuilder('\OCA\Files_external\Service\GlobalStoragesService')
+ ->disableOriginalConstructor()
+ ->getMock();
$this->controller = new GlobalStoragesController(
'files_external',
diff --git a/apps/files_external/tests/controller/storagescontrollertest.php b/apps/files_external/tests/controller/storagescontrollertest.php
index 86874ef9786..2b0ee7a14ea 100644
--- a/apps/files_external/tests/controller/storagescontrollertest.php
+++ b/apps/files_external/tests/controller/storagescontrollertest.php
@@ -1,6 +1,7 @@
<?php
/**
* @author Vincent Petry <pvince81@owncloud.com>
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
@@ -47,17 +48,56 @@ abstract class StoragesControllerTest extends \Test\TestCase {
\OC_Mount_Config::$skipTest = false;
}
+ protected function getBackendMock($class = '\OCA\Files_External\Lib\Backend\SMB', $storageClass = '\OC\Files\Storage\SMB') {
+ $backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $backend->method('getStorageClass')
+ ->willReturn($storageClass);
+ $backend->method('getIdentifier')
+ ->willReturn('identifier:'.$class);
+ return $backend;
+ }
+
+ protected function getAuthMechMock($scheme = 'null', $class = '\OCA\Files_External\Lib\Auth\NullMechanism') {
+ $authMech = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $authMech->method('getScheme')
+ ->willReturn($scheme);
+ $authMech->method('getIdentifier')
+ ->willReturn('identifier:'.$class);
+
+ return $authMech;
+ }
+
public function testAddStorage() {
+ $authMech = $this->getAuthMechMock();
+ $authMech->method('validateStorage')
+ ->willReturn(true);
+ $backend = $this->getBackendMock();
+ $backend->method('validateStorage')
+ ->willReturn(true);
+ $backend->method('isVisibleFor')
+ ->willReturn(true);
+
$storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('mount');
+ $storageConfig->setBackend($backend);
+ $storageConfig->setAuthMechanism($authMech);
+ $storageConfig->setBackendOptions([]);
$this->service->expects($this->once())
+ ->method('createStorage')
+ ->will($this->returnValue($storageConfig));
+ $this->service->expects($this->once())
->method('addStorage')
->will($this->returnValue($storageConfig));
$response = $this->controller->create(
'mount',
'\OC\Files\Storage\SMB',
+ '\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@@ -66,15 +106,30 @@ abstract class StoragesControllerTest extends \Test\TestCase {
);
$data = $response->getData();
- $this->assertEquals($storageConfig, $data);
$this->assertEquals(Http::STATUS_CREATED, $response->getStatus());
+ $this->assertEquals($storageConfig, $data);
}
public function testUpdateStorage() {
+ $authMech = $this->getAuthMechMock();
+ $authMech->method('validateStorage')
+ ->willReturn(true);
+ $backend = $this->getBackendMock();
+ $backend->method('validateStorage')
+ ->willReturn(true);
+ $backend->method('isVisibleFor')
+ ->willReturn(true);
+
$storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('mount');
+ $storageConfig->setBackend($backend);
+ $storageConfig->setAuthMechanism($authMech);
+ $storageConfig->setBackendOptions([]);
$this->service->expects($this->once())
+ ->method('createStorage')
+ ->will($this->returnValue($storageConfig));
+ $this->service->expects($this->once())
->method('updateStorage')
->will($this->returnValue($storageConfig));
@@ -82,6 +137,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
1,
'mount',
'\OC\Files\Storage\SMB',
+ '\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@@ -90,8 +146,8 @@ abstract class StoragesControllerTest extends \Test\TestCase {
);
$data = $response->getData();
- $this->assertEquals($storageConfig, $data);
$this->assertEquals(Http::STATUS_OK, $response->getStatus());
+ $this->assertEquals($storageConfig, $data);
}
function mountPointNamesProvider() {
@@ -106,6 +162,15 @@ abstract class StoragesControllerTest extends \Test\TestCase {
* @dataProvider mountPointNamesProvider
*/
public function testAddOrUpdateStorageInvalidMountPoint($mountPoint) {
+ $storageConfig = new StorageConfig(1);
+ $storageConfig->setMountPoint($mountPoint);
+ $storageConfig->setBackend($this->getBackendMock());
+ $storageConfig->setAuthMechanism($this->getAuthMechMock());
+ $storageConfig->setBackendOptions([]);
+
+ $this->service->expects($this->exactly(2))
+ ->method('createStorage')
+ ->will($this->returnValue($storageConfig));
$this->service->expects($this->never())
->method('addStorage');
$this->service->expects($this->never())
@@ -114,6 +179,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$response = $this->controller->create(
$mountPoint,
'\OC\Files\Storage\SMB',
+ '\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@@ -127,6 +193,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
1,
$mountPoint,
'\OC\Files\Storage\SMB',
+ '\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@@ -138,6 +205,9 @@ abstract class StoragesControllerTest extends \Test\TestCase {
}
public function testAddOrUpdateStorageInvalidBackend() {
+ $this->service->expects($this->exactly(2))
+ ->method('createStorage')
+ ->will($this->throwException(new \InvalidArgumentException()));
$this->service->expects($this->never())
->method('addStorage');
$this->service->expects($this->never())
@@ -146,6 +216,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$response = $this->controller->create(
'mount',
'\OC\Files\Storage\InvalidStorage',
+ '\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@@ -159,6 +230,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
1,
'mount',
'\OC\Files\Storage\InvalidStorage',
+ '\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@@ -170,6 +242,24 @@ abstract class StoragesControllerTest extends \Test\TestCase {
}
public function testUpdateStorageNonExisting() {
+ $authMech = $this->getAuthMechMock();
+ $authMech->method('validateStorage')
+ ->willReturn(true);
+ $backend = $this->getBackendMock();
+ $backend->method('validateStorage')
+ ->willReturn(true);
+ $backend->method('isVisibleFor')
+ ->willReturn(true);
+
+ $storageConfig = new StorageConfig(255);
+ $storageConfig->setMountPoint('mount');
+ $storageConfig->setBackend($backend);
+ $storageConfig->setAuthMechanism($authMech);
+ $storageConfig->setBackendOptions([]);
+
+ $this->service->expects($this->once())
+ ->method('createStorage')
+ ->will($this->returnValue($storageConfig));
$this->service->expects($this->once())
->method('updateStorage')
->will($this->throwException(new NotFoundException()));
@@ -178,6 +268,7 @@ abstract class StoragesControllerTest extends \Test\TestCase {
255,
'mount',
'\OC\Files\Storage\SMB',
+ '\OCA\Files_External\Lib\Auth\NullMechanism',
array(),
[],
[],
@@ -206,9 +297,12 @@ abstract class StoragesControllerTest extends \Test\TestCase {
}
public function testGetStorage() {
+ $backend = $this->getBackendMock();
+ $authMech = $this->getAuthMechMock();
$storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('test');
- $storageConfig->setBackendClass('\OC\Files\Storage\SMB');
+ $storageConfig->setBackend($backend);
+ $storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions(['user' => 'test', 'password', 'password123']);
$storageConfig->setMountOptions(['priority' => false]);
@@ -221,4 +315,66 @@ abstract class StoragesControllerTest extends \Test\TestCase {
$this->assertEquals(Http::STATUS_OK, $response->getStatus());
$this->assertEquals($storageConfig, $response->getData());
}
+
+ public function validateStorageProvider() {
+ return [
+ [true, true, true],
+ [false, true, false],
+ [true, false, false],
+ [false, false, false]
+ ];
+ }
+
+ /**
+ * @dataProvider validateStorageProvider
+ */
+ public function testValidateStorage($backendValidate, $authMechValidate, $expectSuccess) {
+ $backend = $this->getBackendMock();
+ $backend->method('validateStorage')
+ ->willReturn($backendValidate);
+ $backend->method('isVisibleFor')
+ ->willReturn(true);
+
+ $authMech = $this->getAuthMechMock();
+ $authMech->method('validateStorage')
+ ->will($this->returnValue($authMechValidate));
+
+ $storageConfig = new StorageConfig();
+ $storageConfig->setMountPoint('mount');
+ $storageConfig->setBackend($backend);
+ $storageConfig->setAuthMechanism($authMech);
+ $storageConfig->setBackendOptions([]);
+
+ $this->service->expects($this->once())
+ ->method('createStorage')
+ ->will($this->returnValue($storageConfig));
+
+ if ($expectSuccess) {
+ $this->service->expects($this->once())
+ ->method('addStorage')
+ ->with($storageConfig)
+ ->will($this->returnValue($storageConfig));
+ } else {
+ $this->service->expects($this->never())
+ ->method('addStorage');
+ }
+
+ $response = $this->controller->create(
+ 'mount',
+ '\OC\Files\Storage\SMB',
+ '\OCA\Files_External\Lib\Auth\NullMechanism',
+ array(),
+ [],
+ [],
+ [],
+ null
+ );
+
+ if ($expectSuccess) {
+ $this->assertEquals(Http::STATUS_CREATED, $response->getStatus());
+ } else {
+ $this->assertEquals(Http::STATUS_UNPROCESSABLE_ENTITY, $response->getStatus());
+ }
+ }
+
}
diff --git a/apps/files_external/tests/controller/userstoragescontrollertest.php b/apps/files_external/tests/controller/userstoragescontrollertest.php
index f9b4c5b2681..9f1a8df8d2e 100644
--- a/apps/files_external/tests/controller/userstoragescontrollertest.php
+++ b/apps/files_external/tests/controller/userstoragescontrollertest.php
@@ -24,6 +24,8 @@ use \OCA\Files_external\Controller\UserStoragesController;
use \OCA\Files_external\Service\UserStoragesService;
use \OCP\AppFramework\Http;
use \OCA\Files_external\NotFoundException;
+use \OCA\Files_External\Lib\StorageConfig;
+use \OCA\Files_External\Service\BackendService;
class UserStoragesControllerTest extends StoragesControllerTest {
@@ -44,41 +46,24 @@ class UserStoragesControllerTest extends StoragesControllerTest {
$this->getMock('\OCP\IL10N'),
$this->service
);
-
- $config = \OC::$server->getConfig();
-
- $this->oldAllowedBackends = $config->getAppValue(
- 'files_external',
- 'user_mounting_backends',
- ''
- );
- $config->setAppValue(
- 'files_external',
- 'user_mounting_backends',
- '\OC\Files\Storage\SMB'
- );
}
- public function tearDown() {
- $config = \OC::$server->getConfig();
- $config->setAppValue(
- 'files_external',
- 'user_mounting_backends',
- $this->oldAllowedBackends
- );
- parent::tearDown();
- }
+ public function testAddOrUpdateStorageDisallowedBackend() {
+ $backend = $this->getBackendMock();
+ $backend->method('isVisibleFor')
+ ->with(BackendService::VISIBILITY_PERSONAL)
+ ->willReturn(false);
+ $authMech = $this->getAuthMechMock();
- function disallowedBackendClassProvider() {
- return array(
- array('\OC\Files\Storage\Local'),
- array('\OC\Files\Storage\FTP'),
- );
- }
- /**
- * @dataProvider disallowedBackendClassProvider
- */
- public function testAddOrUpdateStorageDisallowedBackend($backendClass) {
+ $storageConfig = new StorageConfig(1);
+ $storageConfig->setMountPoint('mount');
+ $storageConfig->setBackend($backend);
+ $storageConfig->setAuthMechanism($authMech);
+ $storageConfig->setBackendOptions([]);
+
+ $this->service->expects($this->exactly(2))
+ ->method('createStorage')
+ ->will($this->returnValue($storageConfig));
$this->service->expects($this->never())
->method('addStorage');
$this->service->expects($this->never())
@@ -86,7 +71,8 @@ class UserStoragesControllerTest extends StoragesControllerTest {
$response = $this->controller->create(
'mount',
- $backendClass,
+ '\OC\Files\Storage\SMB',
+ '\Auth\Mechanism',
array(),
[],
[],
@@ -99,7 +85,8 @@ class UserStoragesControllerTest extends StoragesControllerTest {
$response = $this->controller->update(
1,
'mount',
- $backendClass,
+ '\OC\Files\Storage\SMB',
+ '\Auth\Mechanism',
array(),
[],
[],
diff --git a/apps/files_external/tests/definitionparameterttest.php b/apps/files_external/tests/definitionparameterttest.php
new file mode 100644
index 00000000000..6be00508698
--- /dev/null
+++ b/apps/files_external/tests/definitionparameterttest.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Tests;
+
+use \OCA\Files_External\Lib\DefinitionParameter as Param;
+
+class DefinitionParameterTest extends \Test\TestCase {
+
+ public function testJsonSerialization() {
+ $param = new Param('foo', 'bar');
+ $this->assertEquals('bar', $param->jsonSerialize());
+
+ $param->setType(Param::VALUE_BOOLEAN);
+ $this->assertEquals('!bar', $param->jsonSerialize());
+
+ $param->setType(Param::VALUE_PASSWORD);
+ $param->setFlag(Param::FLAG_OPTIONAL);
+ $this->assertEquals('&*bar', $param->jsonSerialize());
+
+ $param->setType(Param::VALUE_HIDDEN);
+ $param->setFlags(Param::FLAG_NONE);
+ $this->assertEquals('#bar', $param->jsonSerialize());
+ }
+
+ public function validateValueProvider() {
+ return [
+ [Param::VALUE_TEXT, Param::FLAG_NONE, 'abc', true],
+ [Param::VALUE_TEXT, Param::FLAG_NONE, '', false],
+ [Param::VALUE_TEXT, Param::FLAG_OPTIONAL, '', true],
+
+ [Param::VALUE_BOOLEAN, Param::FLAG_NONE, false, true],
+ [Param::VALUE_BOOLEAN, Param::FLAG_NONE, 123, false],
+
+ [Param::VALUE_PASSWORD, Param::FLAG_NONE, 'foobar', true],
+ [Param::VALUE_PASSWORD, Param::FLAG_NONE, '', false],
+
+ [Param::VALUE_HIDDEN, Param::FLAG_NONE, '', false]
+ ];
+ }
+
+ /**
+ * @dataProvider validateValueProvider
+ */
+ public function testValidateValue($type, $flags, $value, $success) {
+ $param = new Param('foo', 'bar');
+ $param->setType($type);
+ $param->setFlags($flags);
+
+ $this->assertEquals($success, $param->validateValue($value));
+ }
+}
diff --git a/apps/files_external/tests/dependencytraittest.php b/apps/files_external/tests/dependencytraittest.php
new file mode 100644
index 00000000000..5706d97053d
--- /dev/null
+++ b/apps/files_external/tests/dependencytraittest.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Tests;
+
+use \OCA\Files_External\Lib\MissingDependency;
+
+class DependencyTraitTest extends \Test\TestCase {
+
+ public function testCheckDependencies() {
+ $trait = $this->getMockForTrait('\OCA\Files_External\Lib\DependencyTrait');
+ $trait->setDependencyCheck(function() {
+ return [
+ (new MissingDependency('dependency'))->setMessage('missing dependency'),
+ (new MissingDependency('program'))->setMessage('cannot find program'),
+ ];
+ });
+
+ $dependencies = $trait->checkDependencies();
+ $this->assertCount(2, $dependencies);
+ $this->assertEquals('dependency', $dependencies[0]->getDependency());
+ $this->assertEquals('missing dependency', $dependencies[0]->getMessage());
+ $this->assertEquals('program', $dependencies[1]->getDependency());
+ $this->assertEquals('cannot find program', $dependencies[1]->getMessage());
+ }
+
+}
diff --git a/apps/files_external/tests/dynamicmountconfig.php b/apps/files_external/tests/dynamicmountconfig.php
deleted file mode 100644
index 48791ca89a5..00000000000
--- a/apps/files_external/tests/dynamicmountconfig.php
+++ /dev/null
@@ -1,104 +0,0 @@
-<?php
-/**
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-require_once __DIR__ . '/../../../lib/base.php';
-
-/**
- * Class Test_Mount_Config_Dummy_Backend
- */
-class Test_Mount_Config_Dummy_Backend {
- public static $checkDependencies = true;
-
- public static function checkDependencies() {
- return self::$checkDependencies;
- }
-}
-
-/**
- * Class Test_Dynamic_Mount_Config
- */
-class Test_Dynamic_Mount_Config extends \Test\TestCase {
-
- private $backup;
-
- public function testRegistration() {
-
- // second registration shall return false
- $result = OC_Mount_Config::registerBackend('Test_Mount_Config_Dummy_Backend', array(
- 'backend' => 'Test Dummy',
- 'configuration' => array(),
- 'has_dependencies' => true));
-
- $this->assertTrue($result);
- }
-
- public function testDependencyGetBackend() {
-
- // is the backend listed?
- Test_Mount_Config_Dummy_Backend::$checkDependencies = true;
- $backEnds = OC_Mount_Config::getBackends();
- $this->assertArrayHasKey('Test_Mount_Config_Dummy_Backend', $backEnds);
-
- // backend shall not be listed
- Test_Mount_Config_Dummy_Backend::$checkDependencies = false;
-
- $backEnds = OC_Mount_Config::getBackends();
- $this->assertArrayNotHasKey('Test_Mount_Config_Dummy_Backend', $backEnds);
-
- }
-
- public function testCheckDependencies() {
-
- Test_Mount_Config_Dummy_Backend::$checkDependencies = true;
- $message = OC_Mount_Config::checkDependencies();
- $this->assertEmpty($message);
-
- // backend shall not be listed
- Test_Mount_Config_Dummy_Backend::$checkDependencies = array('dummy');
-
- $message = OC_Mount_Config::checkDependencies();
- $this->assertEquals('<br /><b>Note:</b> "dummy" is not installed. Mounting of <i>Test Dummy</i> is not possible. Please ask your system administrator to install it.',
- $message);
-
- }
-
- protected function setUp() {
- parent::setUp();
-
- $this->backup = OC_Mount_Config::setUp();
-
- // register dummy backend
- $result = OC_Mount_Config::registerBackend('Test_Mount_Config_Dummy_Backend', array(
- 'backend' => 'Test Dummy',
- 'configuration' => array(),
- 'has_dependencies' => true));
-
- $this->assertTrue($result);
- }
-
- protected function tearDown()
- {
- OC_Mount_Config::setUp($this->backup);
- parent::tearDown();
- }
-}
diff --git a/apps/files_external/tests/frontenddefinitiontraittest.php b/apps/files_external/tests/frontenddefinitiontraittest.php
new file mode 100644
index 00000000000..871a87d4c52
--- /dev/null
+++ b/apps/files_external/tests/frontenddefinitiontraittest.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Files_External\Tests;
+
+class FrontendDefinitionTraitTest extends \Test\TestCase {
+
+ public function testJsonSerialization() {
+ $param = $this->getMockBuilder('\OCA\Files_External\Lib\DefinitionParameter')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $param->method('getName')->willReturn('foo');
+
+ $trait = $this->getMockForTrait('\OCA\Files_External\Lib\FrontendDefinitionTrait');
+ $trait->setText('test');
+ $trait->addParameters([$param]);
+ $trait->setCustomJs('foo/bar.js');
+
+ $json = $trait->jsonSerializeDefinition();
+
+ $this->assertEquals('test', $json['name']);
+ $this->assertEquals('foo/bar.js', $json['custom']);
+
+ $configuration = $json['configuration'];
+ $this->assertArrayHasKey('foo', $configuration);
+ }
+
+ public function validateStorageProvider() {
+ return [
+ [true, ['foo' => true, 'bar' => true, 'baz' => true]],
+ [false, ['foo' => true, 'bar' => false]]
+ ];
+ }
+
+ /**
+ * @dataProvider validateStorageProvider
+ */
+ public function testValidateStorage($expectedSuccess, $params) {
+ $backendParams = [];
+ foreach ($params as $name => $valid) {
+ $param = $this->getMockBuilder('\OCA\Files_External\Lib\DefinitionParameter')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $param->method('getName')
+ ->willReturn($name);
+ $param->expects($this->once())
+ ->method('validateValue')
+ ->willReturn($valid);
+ $backendParams[] = $param;
+ }
+
+ $storageConfig = $this->getMockBuilder('\OCA\Files_External\Lib\StorageConfig')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $storageConfig->expects($this->once())
+ ->method('getBackendOptions')
+ ->willReturn([]);
+
+ $trait = $this->getMockForTrait('\OCA\Files_External\Lib\FrontendDefinitionTrait');
+ $trait->setText('test');
+ $trait->addParameters($backendParams);
+
+ $this->assertEquals($expectedSuccess, $trait->validateStorageDefinition($storageConfig));
+ }
+}
diff --git a/apps/files_external/tests/js/settingsSpec.js b/apps/files_external/tests/js/settingsSpec.js
index 7cb86d7270b..67a81277124 100644
--- a/apps/files_external/tests/js/settingsSpec.js
+++ b/apps/files_external/tests/js/settingsSpec.js
@@ -39,6 +39,7 @@ describe('OCA.External.Settings tests', function() {
'<option value="\\OC\\AnotherTestBackend">Another Test Backend</option>' +
'</select>' +
'</td>' +
+ '<td class="authentication"></td>' +
'<td class="configuration"></td>' +
'<td class="applicable">' +
'<input type="hidden" class="applicableUsers">' +
@@ -58,6 +59,9 @@ describe('OCA.External.Settings tests', function() {
'field1': 'Display Name 1',
'field2': '&Display Name 2'
},
+ 'authSchemes': {
+ 'builtin': true,
+ },
'priority': 11
},
'\\OC\\AnotherTestBackend': {
@@ -66,10 +70,23 @@ describe('OCA.External.Settings tests', function() {
'field1': 'Display Name 1',
'field2': '&Display Name 2'
},
+ 'authSchemes': {
+ 'builtin': true,
+ },
'priority': 12
}
}
);
+
+ $('#externalStorage #addMountPoint .authentication:first').data('mechanisms', {
+ 'mechanism1': {
+ 'name': 'Mechanism 1',
+ 'configuration': {
+ },
+ 'scheme': 'builtin',
+ },
+ });
+
});
afterEach(function() {
select2Stub.restore();
@@ -80,7 +97,7 @@ describe('OCA.External.Settings tests', function() {
var view;
function selectBackend(backendName) {
- view.$el.find('.selectBackend:first').val('\\OC\\TestBackend').trigger('change');
+ view.$el.find('.selectBackend:first').val(backendName).trigger('change');
}
beforeEach(function() {
@@ -139,7 +156,8 @@ describe('OCA.External.Settings tests', function() {
var request = fakeServer.requests[0];
expect(request.url).toEqual(OC.webroot + '/index.php/apps/files_external/globalstorages');
expect(JSON.parse(request.requestBody)).toEqual({
- backendClass: '\\OC\\TestBackend',
+ backend: '\\OC\\TestBackend',
+ authMechanism: 'mechanism1',
backendOptions: {
'field1': 'test',
'field2': ''
diff --git a/apps/files_external/tests/mountconfig.php b/apps/files_external/tests/mountconfig.php
deleted file mode 100644
index b76ba0a39a6..00000000000
--- a/apps/files_external/tests/mountconfig.php
+++ /dev/null
@@ -1,1157 +0,0 @@
-<?php
-/**
- * @author Björn Schießle <schiessle@owncloud.com>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Robin McCorkell <rmccorkell@karoshi.org.uk>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2015, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-class Test_Mount_Config_Dummy_Storage extends \OC\Files\Storage\Common {
- public function __construct($params) {
- if (isset($params['simulateFail']) && $params['simulateFail'] == true) {
- throw new \Exception('Simulated config validation fail');
- }
- }
-
- public function getId() {
- return 'dummy_storage';
- }
-
- public function mkdir($path) {
- return false;
- }
-
- public function rmdir($path) {
- return false;
- }
-
- public function opendir($path) {
- return false;
- }
-
- public function filetype($path) {
- return false;
- }
-
- public function file_exists($path) {
- return false;
- }
-
- public function unlink($path) {
- return false;
- }
-
- public function fopen($path, $mode) {
- return false;
- }
-
- public function touch($path, $mtime = null) {
- return false;
- }
-
- public function stat($path) {
- return false;
- }
-
- public function test() {
- return true;
- }
-}
-
-class Test_Mount_Config_Storage_No_Personal extends Test_Mount_Config_Dummy_Storage {
-}
-
-class Test_Mount_Config_Hook_Test {
- static $signal;
- static $params;
-
- public static function setUpHooks() {
- self::clear();
- \OCP\Util::connectHook(
- \OC\Files\Filesystem::CLASSNAME,
- \OC\Files\Filesystem::signal_create_mount,
- '\Test_Mount_Config_Hook_Test', 'createHookCallback');
- \OCP\Util::connectHook(
- \OC\Files\Filesystem::CLASSNAME,
- \OC\Files\Filesystem::signal_delete_mount,
- '\Test_Mount_Config_Hook_Test', 'deleteHookCallback');
- }
-
- public static function clear() {
- self::$signal = null;
- self::$params = null;
- }
-
- public static function createHookCallback($params) {
- self::$signal = \OC\Files\Filesystem::signal_create_mount;
- self::$params = $params;
- }
-
- public static function deleteHookCallback($params) {
- self::$signal = \OC\Files\Filesystem::signal_delete_mount;
- self::$params = $params;
- }
-
- public static function getLastCall() {
- return array(self::$signal, self::$params);
- }
-}
-
-/**
- * Class Test_Mount_Config
- */
-class Test_Mount_Config extends \Test\TestCase {
-
- private $dataDir;
- private $userHome;
- private $oldAllowedBackends;
-
- const TEST_USER1 = 'user1';
- const TEST_USER2 = 'user2';
- const TEST_GROUP1 = 'group1';
- const TEST_GROUP1B = 'group1b';
- const TEST_GROUP2 = 'group2';
- const TEST_GROUP2B = 'group2b';
-
- protected function setUp() {
- parent::setUp();
-
- OC_Mount_Config::registerBackend('Test_Mount_Config_Dummy_Storage', array(
- 'backend' => 'dummy',
- 'priority' => 150,
- 'configuration' => array()
- )
- );
- OC_Mount_Config::registerBackend('Test_Mount_Config_Storage_No_Personal', array(
- 'backend' => 'dummy no personal',
- 'priority' => 150,
- 'configuration' => array()
- )
- );
-
- \OC_User::createUser(self::TEST_USER1, self::TEST_USER1);
- \OC_User::createUser(self::TEST_USER2, self::TEST_USER2);
-
- \OC_Group::createGroup(self::TEST_GROUP1);
- \OC_Group::createGroup(self::TEST_GROUP1B);
- \OC_Group::addToGroup(self::TEST_USER1, self::TEST_GROUP1);
- \OC_Group::addToGroup(self::TEST_USER1, self::TEST_GROUP1B);
- \OC_Group::createGroup(self::TEST_GROUP2);
- \OC_Group::createGroup(self::TEST_GROUP2B);
- \OC_Group::addToGroup(self::TEST_USER2, self::TEST_GROUP2);
- \OC_Group::addToGroup(self::TEST_USER2, self::TEST_GROUP2B);
-
- \OC_User::setUserId(self::TEST_USER1);
- $this->userHome = \OC_User::getHome(self::TEST_USER1);
- @mkdir($this->userHome);
-
- $this->dataDir = \OC_Config::getValue(
- 'datadirectory',
- \OC::$SERVERROOT . '/data/'
- );
- $this->oldAllowedBackends = OCP\Config::getAppValue(
- 'files_external',
- 'user_mounting_backends',
- ''
- );
- OCP\Config::setAppValue(
- 'files_external',
- 'user_mounting_backends',
- 'Test_Mount_Config_Dummy_Storage'
- );
-
- OC_Mount_Config::$skipTest = true;
- Test_Mount_Config_Hook_Test::setupHooks();
- }
-
- protected function tearDown() {
- Test_Mount_Config_Hook_Test::clear();
- OC_Mount_Config::$skipTest = false;
-
- \OC_User::deleteUser(self::TEST_USER2);
- \OC_User::deleteUser(self::TEST_USER1);
- \OC_Group::deleteGroup(self::TEST_GROUP1);
- \OC_Group::deleteGroup(self::TEST_GROUP1B);
- \OC_Group::deleteGroup(self::TEST_GROUP2);
- \OC_Group::deleteGroup(self::TEST_GROUP2B);
-
- @unlink($this->dataDir . '/mount.json');
-
- OCP\Config::setAppValue(
- 'files_external',
- 'user_mounting_backends',
- $this->oldAllowedBackends
- );
-
- parent::tearDown();
- }
-
- /**
- * Reads the global config, for checking
- */
- private function readGlobalConfig() {
- $configFile = $this->dataDir . '/mount.json';
- return json_decode(file_get_contents($configFile), true);
- }
-
- private function writeGlobalConfig($config) {
- $configFile = $this->dataDir . '/mount.json';
- file_put_contents($configFile, json_encode($config));
- }
-
- /**
- * Reads the user config, for checking
- */
- private function readUserConfig() {
- $configFile = $this->userHome . '/mount.json';
- return json_decode(file_get_contents($configFile), true);
- }
-
- /**
- * Write the user config, to simulate existing files
- */
- private function writeUserConfig($config) {
- $configFile = $this->userHome . '/mount.json';
- file_put_contents($configFile, json_encode($config));
- }
-
- /**
- * Test mount point validation
- */
- public function testAddMountPointValidation() {
- $storageClass = 'Test_Mount_Config_Dummy_Storage';
- $mountType = 'user';
- $applicable = 'all';
- $isPersonal = false;
- $this->assertFalse(OC_Mount_Config::addMountPoint('', $storageClass, array(), $mountType, $applicable, $isPersonal));
- $this->assertFalse(OC_Mount_Config::addMountPoint('/', $storageClass, array(), $mountType, $applicable, $isPersonal));
- }
-
- /**
- * Test adding a global mount point
- */
- public function testAddGlobalMountPoint() {
- $mountType = OC_Mount_Config::MOUNT_TYPE_USER;
- $applicable = 'all';
- $isPersonal = false;
-
- $storageOptions = array(
- 'host' => 'localhost',
- 'user' => 'testuser',
- 'password' => '12345',
- );
-
- $this->assertEquals(0, OC_Mount_Config::addMountPoint('/ext', 'Test_Mount_Config_Dummy_Storage', $storageOptions, $mountType, $applicable, $isPersonal));
-
- $config = $this->readGlobalConfig();
- $this->assertEquals(1, count($config));
- $this->assertTrue(isset($config[$mountType]));
- $this->assertTrue(isset($config[$mountType][$applicable]));
- $this->assertTrue(isset($config[$mountType][$applicable]['/$user/files/ext']));
- $this->assertEquals(
- 'Test_Mount_Config_Dummy_Storage',
- $config[$mountType][$applicable]['/$user/files/ext']['class']
- );
- }
-
- /**
- * Test adding a personal mount point
- */
- public function testAddMountPointSingleUser() {
- $mountType = OC_Mount_Config::MOUNT_TYPE_USER;
- $applicable = self::TEST_USER1;
- $isPersonal = true;
-
- $storageOptions = array(
- 'host' => 'localhost',
- 'user' => 'testuser',
- 'password' => '12345',
- );
-
- $this->assertEquals(0, OC_Mount_Config::addMountPoint('/ext', 'Test_Mount_Config_Dummy_Storage', $storageOptions, $mountType, $applicable, $isPersonal));
-
- $config = $this->readUserConfig();
- $this->assertEquals(1, count($config));
- $this->assertTrue(isset($config[$mountType]));
- $this->assertTrue(isset($config[$mountType][$applicable]));
- $this->assertTrue(isset($config[$mountType][$applicable]['/' . self::TEST_USER1 . '/files/ext']));
- $this->assertEquals(
- 'Test_Mount_Config_Dummy_Storage',
- $config[$mountType][$applicable]['/' . self::TEST_USER1 . '/files/ext']['class']
- );
- }
-
- /**
- * Test adding a personal mount point using disallowed backend
- */
- public function testAddDisallowedBackendMountPointSingleUser() {
- $mountType = OC_Mount_Config::MOUNT_TYPE_USER;
- $applicable = self::TEST_USER1;
- $isPersonal = true;
-
- // local
- $this->assertFalse(OC_Mount_Config::addMountPoint('/ext', '\OC\Files\Storage\Local', array(), $mountType, $applicable, $isPersonal));
-
- $storageOptions = array(
- 'host' => 'localhost',
- 'user' => 'testuser',
- 'password' => '12345',
- );
-
- // non-local but forbidden
- $this->assertFalse(OC_Mount_Config::addMountPoint('/ext', 'Test_Mount_Config_Storage_No_Personal', $storageOptions, $mountType, $applicable, $isPersonal));
-
- $this->assertFalse(file_exists($this->userHome . '/mount.json'));
- }
-
- /**
- * Test adding a mount point with an non-existant backend
- */
- public function testAddMountPointUnexistClass() {
- $storageClass = 'Unexist_Storage';
- $mountType = OC_Mount_Config::MOUNT_TYPE_USER;
- $applicable = self::TEST_USER1;
- $isPersonal = false;
- $this->assertFalse(OC_Mount_Config::addMountPoint('/ext', $storageClass, array(), $mountType, $applicable, $isPersonal));
-
- }
-
- /**
- * Provider for testing configurations with different
- * "applicable" values (all, user, groups)
- */
- public function applicableConfigProvider() {
- return array(
- // applicable to "all"
- array(
- OC_Mount_Config::MOUNT_TYPE_USER,
- 'all',
- array(
- 'users' => array('all'),
- 'groups' => array()
- )
- ),
- // applicable to single user
- array(
- OC_Mount_Config::MOUNT_TYPE_USER,
- self::TEST_USER1,
- array(
- 'users' => array(self::TEST_USER1),
- 'groups' => array()
- )
- ),
- // applicable to single group
- array(
- OC_Mount_Config::MOUNT_TYPE_GROUP,
- self::TEST_GROUP1,
- array(
- 'users' => array(),
- 'groups' => array(self::TEST_GROUP1)
- )
- ),
- );
- }
-
- /**
- * Test reading and writing global config
- *
- * @dataProvider applicableConfigProvider
- */
- public function testReadWriteGlobalConfig($mountType, $applicable, $expectApplicableArray) {
-
- $mountType = $mountType;
- $applicable = $applicable;
- $isPersonal = false;
- $options = array(
- 'host' => 'smbhost',
- 'user' => 'smbuser',
- 'password' => 'smbpassword',
- 'share' => 'smbshare',
- 'root' => 'smbroot'
- );
-
- // write config
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- '/ext',
- 'Test_Mount_Config_Dummy_Storage',
- $options,
- $mountType,
- $applicable,
- $isPersonal
- )
- );
-
- // re-read config
- $config = OC_Mount_Config::getSystemMountPoints();
- $this->assertEquals(1, count($config));
- $this->assertEquals('Test_Mount_Config_Dummy_Storage', $config[0]['class']);
- $this->assertEquals('ext', $config[0]['mountpoint']);
- $this->assertEquals($expectApplicableArray, $config[0]['applicable']);
- $savedOptions = $config[0]['options'];
- $this->assertEquals($options, $savedOptions);
- // key order needs to be preserved for the UI...
- $this->assertEquals(array_keys($options), array_keys($savedOptions));
- }
-
- /**
- * Test reading and writing config
- */
- public function testReadWritePersonalConfig() {
-
- $mountType = OC_Mount_Config::MOUNT_TYPE_USER;
- $applicable = self::TEST_USER1;
- $isPersonal = true;
- $options = array(
- 'host' => 'smbhost',
- 'user' => 'smbuser',
- 'password' => 'smbpassword',
- 'share' => 'smbshare',
- 'root' => 'smbroot'
- );
-
- // write config
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- '/ext',
- 'Test_Mount_Config_Dummy_Storage',
- $options,
- $mountType,
- $applicable,
- $isPersonal
- )
- );
-
- // re-read config
- $config = OC_Mount_Config::getPersonalMountPoints();
- $this->assertEquals(1, count($config));
- $this->assertEquals('Test_Mount_Config_Dummy_Storage', $config[0]['class']);
- $this->assertEquals('ext', $config[0]['mountpoint']);
- $savedOptions = $config[0]['options'];
- $this->assertEquals($options, $savedOptions);
- // key order needs to be preserved for the UI...
- $this->assertEquals(array_keys($options), array_keys($savedOptions));
- }
-
- public function testHooks() {
- $mountPoint = '/test';
- $mountType = 'user';
- $applicable = 'all';
- $isPersonal = false;
-
- $mountConfig = array(
- 'host' => 'smbhost',
- 'user' => 'smbuser',
- 'password' => 'smbpassword',
- 'share' => 'smbshare',
- 'root' => 'smbroot'
- );
-
- // write config
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- $mountPoint,
- 'Test_Mount_Config_Dummy_Storage',
- $mountConfig,
- $mountType,
- $applicable,
- $isPersonal
- )
- );
-
- list($hookName, $params) = Test_Mount_Config_Hook_Test::getLastCall();
- $this->assertEquals(
- \OC\Files\Filesystem::signal_create_mount,
- $hookName
- );
- $this->assertEquals(
- $mountPoint,
- $params[\OC\Files\Filesystem::signal_param_path]
- );
- $this->assertEquals(
- $mountType,
- $params[\OC\Files\Filesystem::signal_param_mount_type]
- );
- $this->assertEquals(
- $applicable,
- $params[\OC\Files\Filesystem::signal_param_users]
- );
-
- Test_Mount_Config_Hook_Test::clear();
-
- // edit
- $mountConfig['host'] = 'anothersmbhost';
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- $mountPoint,
- 'Test_Mount_Config_Dummy_Storage',
- $mountConfig,
- $mountType,
- $applicable,
- $isPersonal
- )
- );
-
- // hook must not be called on edit
- list($hookName, $params) = Test_Mount_Config_Hook_Test::getLastCall();
- $this->assertEquals(
- null,
- $hookName
- );
-
- Test_Mount_Config_Hook_Test::clear();
-
- $this->assertTrue(
- OC_Mount_Config::removeMountPoint(
- $mountPoint,
- $mountType,
- $applicable,
- $isPersonal
- )
- );
-
- list($hookName, $params) = Test_Mount_Config_Hook_Test::getLastCall();
- $this->assertEquals(
- \OC\Files\Filesystem::signal_delete_mount,
- $hookName
- );
- $this->assertEquals(
- $mountPoint,
- $params[\OC\Files\Filesystem::signal_param_path]
- );
- $this->assertEquals(
- $mountType,
- $params[\OC\Files\Filesystem::signal_param_mount_type]
- );
- $this->assertEquals(
- $applicable,
- $params[\OC\Files\Filesystem::signal_param_users]
- );
- }
-
- /**
- * Test password obfuscation
- */
- public function testPasswordObfuscation() {
-
- $mountType = OC_Mount_Config::MOUNT_TYPE_USER;
- $applicable = self::TEST_USER1;
- $isPersonal = true;
- $mountConfig = array(
- 'host' => 'smbhost',
- 'user' => 'smbuser',
- 'password' => 'smbpassword',
- 'share' => 'smbshare',
- 'root' => 'smbroot'
- );
-
- // write config
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- '/ext',
- 'Test_Mount_Config_Dummy_Storage',
- $mountConfig,
- $mountType,
- $applicable,
- $isPersonal
- )
- );
-
- // note: password re-reading is covered by testReadWritePersonalConfig
-
- // check that password inside the file is NOT in plain text
- $config = $this->readUserConfig();
- $savedConfig = $config[$mountType][$applicable]['/' . self::TEST_USER1 . '/files/ext']['options'];
-
- // no more clear text password in file (kept because of key order)
- $this->assertEquals('', $savedConfig['password']);
-
- // encrypted password is present
- $this->assertNotEquals($mountConfig['password'], $savedConfig['password_encrypted']);
- }
-
- /**
- * Test read legacy passwords
- */
- public function testReadLegacyPassword() {
-
- $mountType = OC_Mount_Config::MOUNT_TYPE_USER;
- $applicable = self::TEST_USER1;
- $isPersonal = true;
- $mountConfig = array(
- 'host' => 'smbhost',
- 'user' => 'smbuser',
- 'password' => 'smbpassword',
- 'share' => 'smbshare',
- 'root' => 'smbroot'
- );
-
- // write config
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- '/ext',
- 'Test_Mount_Config_Dummy_Storage',
- $mountConfig,
- $mountType,
- $applicable,
- $isPersonal
- )
- );
-
- $config = $this->readUserConfig();
- // simulate non-encrypted password situation
- $config[$mountType][$applicable]['/' . self::TEST_USER1 . '/files/ext']['options']['password'] = 'smbpasswd';
-
- $this->writeUserConfig($config);
-
- // re-read config, password was read correctly
- $config = OC_Mount_Config::getPersonalMountPoints();
- $savedMountConfig = $config[0]['options'];
- $this->assertEquals($mountConfig, $savedMountConfig);
- }
-
- public function testVariableSubstitution() {
- $legacyBackendOptions = [
- 'user' => 'someuser',
- 'password' => 'somepassword',
- 'replacethis' => '$user',
- ];
- $legacyBackendOptions = \OC_Mount_Config::encryptPasswords($legacyBackendOptions);
-
- $legacyConfig = [
- 'class' => '\OC\Files\Storage\SMB',
- 'options' => $legacyBackendOptions,
- 'mountOptions' => ['preview' => false, 'int' => 1],
- ];
- // different mount options
- $legacyConfig2 = [
- 'class' => '\OC\Files\Storage\SMB',
- 'options' => $legacyBackendOptions,
- 'mountOptions' => ['preview' => true, 'string' => 'abc'],
- ];
-
- $json = [
- 'user' => [
- self::TEST_USER1 => [
- '/$user/files/somemount' => $legacyConfig,
- '/$user/files/anothermount' => $legacyConfig2,
- ],
- ],
- ];
-
- $this->writeGlobalConfig($json);
-
- // re-read config, password was read correctly
- $config = OC_Mount_Config::getAbsoluteMountPoints(self::TEST_USER1);
-
- $config1 = $config['/' . self::TEST_USER1 . '/files/somemount'];
- $config2 = $config['/' . self::TEST_USER1 . '/files/anothermount'];
-
- $this->assertSame(self::TEST_USER1, $config1['options']['replacethis']);
- $this->assertSame(self::TEST_USER1, $config1['options']['replacethis']);
- $this->assertSame(1, $config1['mountOptions']['int']);
- $this->assertSame(true, $config2['mountOptions']['preview']);
- $this->assertSame('abc', $config2['mountOptions']['string']);
- }
-
-
- public function mountDataProvider() {
- return array(
- // Tests for visible mount points
- // system mount point for all users
- array(
- false,
- OC_Mount_Config::MOUNT_TYPE_USER,
- 'all',
- self::TEST_USER1,
- true,
- ),
- // system mount point for a specific user
- array(
- false,
- OC_Mount_Config::MOUNT_TYPE_USER,
- self::TEST_USER1,
- self::TEST_USER1,
- true,
- ),
- // system mount point for a specific group
- array(
- false,
- OC_Mount_Config::MOUNT_TYPE_GROUP,
- self::TEST_GROUP1,
- self::TEST_USER1,
- true,
- ),
- // user mount point
- array(
- true,
- OC_Mount_Config::MOUNT_TYPE_USER,
- self::TEST_USER1,
- self::TEST_USER1,
- true,
- ),
-
- // Tests for non-visible mount points
- // system mount point for another user
- array(
- false,
- OC_Mount_Config::MOUNT_TYPE_USER,
- self::TEST_USER2,
- self::TEST_USER1,
- false,
- ),
- // system mount point for a specific group
- array(
- false,
- OC_Mount_Config::MOUNT_TYPE_GROUP,
- self::TEST_GROUP2,
- self::TEST_USER1,
- false,
- ),
- // user mount point
- array(
- true,
- OC_Mount_Config::MOUNT_TYPE_USER,
- self::TEST_USER1,
- self::TEST_USER2,
- false,
- ),
- );
- }
-
- /**
- * Test mount points used at mount time, making sure
- * the configuration is prepared properly.
- *
- * @dataProvider mountDataProvider
- * @param bool $isPersonal true for personal mount point, false for system mount point
- * @param string $mountType mount type
- * @param string $applicable target user/group or "all"
- * @param string $testUser user for which to retrieve the mount points
- * @param bool $expectVisible whether to expect the mount point to be visible for $testUser
- */
- public function testMount($isPersonal, $mountType, $applicable, $testUser, $expectVisible) {
-
- $mountConfig = array(
- 'host' => 'someost',
- 'user' => 'someuser',
- 'password' => 'somepassword',
- 'root' => 'someroot',
- 'share' => '',
- );
-
- // add mount point as "test" user
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- '/ext',
- 'Test_Mount_Config_Dummy_Storage',
- $mountConfig,
- $mountType,
- $applicable,
- $isPersonal
- )
- );
-
- // check mount points in the perspective of user $testUser
- \OC_User::setUserId($testUser);
-
- $mountPoints = OC_Mount_Config::getAbsoluteMountPoints($testUser);
- if ($expectVisible) {
- $this->assertEquals(1, count($mountPoints));
- $this->assertTrue(isset($mountPoints['/' . self::TEST_USER1 . '/files/ext']));
- $this->assertEquals('Test_Mount_Config_Dummy_Storage', $mountPoints['/' . self::TEST_USER1 . '/files/ext']['class']);
- $this->assertEquals($mountConfig, $mountPoints['/' . self::TEST_USER1 . '/files/ext']['options']);
- }
- else {
- $this->assertEquals(0, count($mountPoints));
- }
- }
-
- /**
- * Test the same config for multiple users.
- * The config will be merged by getSystemMountPoints().
- */
- public function testConfigMerging() {
-
- $mountType = OC_Mount_Config::MOUNT_TYPE_USER;
- $isPersonal = false;
- $options = array(
- 'host' => 'smbhost',
- 'user' => 'smbuser',
- 'password' => 'smbpassword',
- 'share' => 'smbshare',
- 'root' => 'smbroot'
- );
-
- // write config
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- '/ext',
- 'Test_Mount_Config_Dummy_Storage',
- $options,
- OC_Mount_Config::MOUNT_TYPE_USER,
- self::TEST_USER1,
- $isPersonal
- )
- );
-
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- '/ext',
- 'Test_Mount_Config_Dummy_Storage',
- $options,
- OC_Mount_Config::MOUNT_TYPE_USER,
- self::TEST_USER2,
- $isPersonal
- )
- );
-
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- '/ext',
- 'Test_Mount_Config_Dummy_Storage',
- $options,
- OC_Mount_Config::MOUNT_TYPE_GROUP,
- self::TEST_GROUP2,
- $isPersonal
- )
- );
-
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- '/ext',
- 'Test_Mount_Config_Dummy_Storage',
- $options,
- OC_Mount_Config::MOUNT_TYPE_GROUP,
- self::TEST_GROUP1,
- $isPersonal
- )
- );
-
- // re-read config
- $config = OC_Mount_Config::getSystemMountPoints();
- $this->assertEquals(1, count($config));
- $this->assertEquals('Test_Mount_Config_Dummy_Storage', $config[0]['class']);
- $this->assertEquals('ext', $config[0]['mountpoint']);
- $this->assertEquals($options, $config[0]['options']);
- $this->assertEquals(array(self::TEST_USER1, self::TEST_USER2), $config[0]['applicable']['users']);
- $this->assertEquals(array(self::TEST_GROUP2, self::TEST_GROUP1), $config[0]['applicable']['groups']);
- }
-
- /**
- * Create then re-read mount points configs where the mount points
- * have the same path, the config must NOT be merged.
- */
- public function testRereadMountpointWithSamePath() {
-
- $mountType = OC_Mount_Config::MOUNT_TYPE_USER;
- $isPersonal = false;
- $options1 = array(
- 'host' => 'smbhost',
- 'user' => 'smbuser',
- 'password' => 'smbpassword',
- 'share' => 'smbshare',
- 'root' => 'smbroot'
- );
-
- // write config
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- '/ext',
- 'Test_Mount_Config_Dummy_Storage',
- $options1,
- $mountType,
- self::TEST_USER1,
- $isPersonal
- )
- );
-
- $options2 = array(
- 'host' => 'anothersmbhost',
- 'user' => 'anothersmbuser',
- 'password' => 'anothersmbpassword',
- 'share' => 'anothersmbshare',
- 'root' => 'anothersmbroot'
- );
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- '/ext',
- 'Test_Mount_Config_Dummy_Storage',
- $options2,
- $mountType,
- self::TEST_USER2,
- $isPersonal
- )
- );
-
- // re-read config
- $config = OC_Mount_Config::getSystemMountPoints();
- $this->assertEquals(2, count($config));
- $this->assertEquals('Test_Mount_Config_Dummy_Storage', $config[0]['class']);
- $this->assertEquals('ext', $config[0]['mountpoint']);
- $this->assertEquals($options1, $config[0]['options']);
- $this->assertEquals('Test_Mount_Config_Dummy_Storage', $config[1]['class']);
- $this->assertEquals('ext', $config[1]['mountpoint']);
- $this->assertEquals($options2, $config[1]['options']);
- }
-
- public function priorityDataProvider() {
- return array(
-
- // test 1 - group vs group
- array(
- array(
- array(
- 'isPersonal' => false,
- 'mountType' => OC_Mount_Config::MOUNT_TYPE_GROUP,
- 'applicable' => self::TEST_GROUP1,
- 'priority' => 50
- ),
- array(
- 'isPersonal' => false,
- 'mountType' => OC_Mount_Config::MOUNT_TYPE_GROUP,
- 'applicable' => self::TEST_GROUP1B,
- 'priority' => 60
- )
- ),
- 1
- ),
- // test 2 - user vs personal
- array(
- array(
- array(
- 'isPersonal' => false,
- 'mountType' => OC_Mount_Config::MOUNT_TYPE_USER,
- 'applicable' => self::TEST_USER1,
- 'priority' => 2000
- ),
- array(
- 'isPersonal' => true,
- 'mountType' => OC_Mount_Config::MOUNT_TYPE_USER,
- 'applicable' => self::TEST_USER1,
- 'priority' => null
- )
- ),
- 1
- ),
- // test 3 - all vs group vs user
- array(
- array(
- array(
- 'isPersonal' => false,
- 'mountType' => OC_Mount_Config::MOUNT_TYPE_USER,
- 'applicable' => 'all',
- 'priority' => 70
- ),
- array(
- 'isPersonal' => false,
- 'mountType' => OC_Mount_Config::MOUNT_TYPE_GROUP,
- 'applicable' => self::TEST_GROUP1,
- 'priority' => 60
- ),
- array(
- 'isPersonal' => false,
- 'mountType' => OC_Mount_Config::MOUNT_TYPE_USER,
- 'applicable' => self::TEST_USER1,
- 'priority' => 50
- )
- ),
- 2
- )
-
- );
- }
-
- /**
- * Ensure priorities are being respected
- * Test user is self::TEST_USER1
- *
- * @dataProvider priorityDataProvider
- * @param array[] $mounts array of associative array of mount parameters:
- * bool $isPersonal
- * string $mountType
- * string $applicable
- * int|null $priority null for personal
- * @param int $expected index of expected visible mount
- */
- public function testPriority($mounts, $expected) {
-
- $mountConfig = array(
- 'host' => 'somehost',
- 'user' => 'someuser',
- 'password' => 'somepassword',
- 'root' => 'someroot',
- 'share' => '',
- );
-
- // Add mount points
- foreach($mounts as $i => $mount) {
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- '/ext',
- 'Test_Mount_Config_Dummy_Storage',
- $mountConfig + array('id' => $i),
- $mount['mountType'],
- $mount['applicable'],
- $mount['isPersonal'],
- $mount['priority']
- )
- );
- }
-
- // Get mount points for user
- $mountPoints = OC_Mount_Config::getAbsoluteMountPoints(self::TEST_USER1);
-
- $this->assertEquals(1, count($mountPoints));
- $this->assertEquals($expected, $mountPoints['/'.self::TEST_USER1.'/files/ext']['options']['id']);
- }
-
- /**
- * Test for persistence of priority when changing mount options
- */
- public function testPriorityPersistence() {
-
- $class = 'Test_Mount_Config_Dummy_Storage';
- $priority = 123;
- $mountConfig = array(
- 'host' => 'somehost',
- 'user' => 'someuser',
- 'password' => 'somepassword',
- 'root' => 'someroot',
- 'share' => '',
- );
-
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- '/ext',
- $class,
- $mountConfig,
- OC_Mount_Config::MOUNT_TYPE_USER,
- self::TEST_USER1,
- false,
- $priority
- )
- );
-
- // Check for correct priority
- $mountPoints = OC_Mount_Config::getAbsoluteMountPoints(self::TEST_USER1);
- $this->assertEquals($priority,
- $mountPoints['/'.self::TEST_USER1.'/files/ext']['priority']);
-
- // Simulate changed mount options (without priority set)
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- '/ext',
- $class,
- $mountConfig,
- OC_Mount_Config::MOUNT_TYPE_USER,
- self::TEST_USER1,
- false
- )
- );
-
- // Check for correct priority
- $mountPoints = OC_Mount_Config::getAbsoluteMountPoints(self::TEST_USER1);
- $this->assertEquals($priority,
- $mountPoints['/'.self::TEST_USER1.'/files/ext']['priority']);
- }
-
- /*
- * Test for correct personal configuration loading in file sharing scenarios
- */
- public function testMultiUserPersonalConfigLoading() {
- $mountConfig = array(
- 'host' => 'somehost',
- 'user' => 'someuser',
- 'password' => 'somepassword',
- 'root' => 'someroot',
- 'share' => '',
- );
-
- // Create personal mount point
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- '/ext',
- 'Test_Mount_Config_Dummy_Storage',
- $mountConfig,
- OC_Mount_Config::MOUNT_TYPE_USER,
- self::TEST_USER1,
- true
- )
- );
-
- // Ensure other user can read mount points
- \OC_User::setUserId(self::TEST_USER2);
- $mountPointsMe = OC_Mount_Config::getAbsoluteMountPoints(self::TEST_USER2);
- $mountPointsOther = OC_Mount_Config::getAbsoluteMountPoints(self::TEST_USER1);
-
- $this->assertEquals(0, count($mountPointsMe));
- $this->assertEquals(1, count($mountPointsOther));
- $this->assertTrue(isset($mountPointsOther['/'.self::TEST_USER1.'/files/ext']));
- $this->assertEquals('Test_Mount_Config_Dummy_Storage',
- $mountPointsOther['/'.self::TEST_USER1.'/files/ext']['class']);
- $this->assertEquals($mountConfig,
- $mountPointsOther['/'.self::TEST_USER1.'/files/ext']['options']);
- }
-
- public function testAllowWritingIncompleteConfigIfStorageContructorFails() {
- $storageClass = 'Test_Mount_Config_Dummy_Storage';
- $mountType = 'user';
- $applicable = 'all';
- $isPersonal = false;
-
- $this->assertEquals(
- 0,
- OC_Mount_Config::addMountPoint(
- '/ext',
- $storageClass,
- array('simulateFail' => true),
- $mountType,
- $applicable,
- $isPersonal
- )
- );
-
- // config can be retrieved afterwards
- $mounts = OC_Mount_Config::getSystemMountPoints();
- $this->assertEquals(1, count($mounts));
-
- // no storage id was set
- $this->assertFalse(isset($mounts[0]['storage_id']));
- }
-}
diff --git a/apps/files_external/tests/service/backendservicetest.php b/apps/files_external/tests/service/backendservicetest.php
new file mode 100644
index 00000000000..08f6b9bf988
--- /dev/null
+++ b/apps/files_external/tests/service/backendservicetest.php
@@ -0,0 +1,152 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\Files_External\Tests\Service;
+
+use \OCA\Files_External\Service\BackendService;
+
+class BackendServiceTest extends \Test\TestCase {
+
+ /** @var \OCP\IConfig */
+ protected $config;
+
+ /** @var \OCP\IL10N */
+ protected $l10n;
+
+ protected function setUp() {
+ $this->config = $this->getMock('\OCP\IConfig');
+ $this->l10n = $this->getMock('\OCP\IL10N');
+ }
+
+ protected function getBackendMock($class) {
+ $backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $backend->method('getIdentifier')->will($this->returnValue('identifier:'.$class));
+ $backend->method('getIdentifierAliases')->will($this->returnValue(['identifier:'.$class]));
+ return $backend;
+ }
+
+ public function testRegisterBackend() {
+ $service = new BackendService($this->config, $this->l10n);
+
+ $backend = $this->getBackendMock('\Foo\Bar');
+
+ $backendAlias = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $backendAlias->method('getIdentifierAliases')
+ ->willReturn(['identifier_real', 'identifier_alias']);
+ $backendAlias->method('getIdentifier')
+ ->willReturn('identifier_real');
+
+ $service->registerBackend($backend);
+ $service->registerBackend($backendAlias);
+
+ $this->assertEquals($backend, $service->getBackend('identifier:\Foo\Bar'));
+ $this->assertEquals($backendAlias, $service->getBackend('identifier_real'));
+ $this->assertEquals($backendAlias, $service->getBackend('identifier_alias'));
+
+ $backends = $service->getBackends();
+ $this->assertCount(2, $backends);
+ $this->assertArrayHasKey('identifier:\Foo\Bar', $backends);
+ $this->assertArrayHasKey('identifier_real', $backends);
+ $this->assertArrayNotHasKey('identifier_alias', $backends);
+ }
+
+ public function testUserMountingBackends() {
+ $this->config->expects($this->exactly(2))
+ ->method('getAppValue')
+ ->will($this->returnValueMap([
+ ['files_external', 'allow_user_mounting', 'yes', 'yes'],
+ ['files_external', 'user_mounting_backends', '', 'identifier:\User\Mount\Allowed,identifier_alias']
+ ]));
+
+ $service = new BackendService($this->config, $this->l10n);
+
+ $backendAllowed = $this->getBackendMock('\User\Mount\Allowed');
+ $backendAllowed->expects($this->never())
+ ->method('removeVisibility');
+ $backendNotAllowed = $this->getBackendMock('\User\Mount\NotAllowed');
+ $backendNotAllowed->expects($this->once())
+ ->method('removeVisibility')
+ ->with(BackendService::VISIBILITY_PERSONAL);
+
+ $backendAlias = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $backendAlias->method('getIdentifierAliases')
+ ->willReturn(['identifier_real', 'identifier_alias']);
+ $backendAlias->expects($this->never())
+ ->method('removeVisibility');
+
+ $service->registerBackend($backendAllowed);
+ $service->registerBackend($backendNotAllowed);
+ $service->registerBackend($backendAlias);
+ }
+
+ public function testGetAvailableBackends() {
+ $service = new BackendService($this->config, $this->l10n);
+
+ $backendAvailable = $this->getBackendMock('\Backend\Available');
+ $backendAvailable->expects($this->once())
+ ->method('checkDependencies')
+ ->will($this->returnValue([]));
+ $backendNotAvailable = $this->getBackendMock('\Backend\NotAvailable');
+ $backendNotAvailable->expects($this->once())
+ ->method('checkDependencies')
+ ->will($this->returnValue([
+ $this->getMockBuilder('\OCA\Files_External\Lib\MissingDependency')
+ ->disableOriginalConstructor()
+ ->getMock()
+ ]));
+
+ $service->registerBackend($backendAvailable);
+ $service->registerBackend($backendNotAvailable);
+
+ $availableBackends = $service->getAvailableBackends();
+ $this->assertArrayHasKey('identifier:\Backend\Available', $availableBackends);
+ $this->assertArrayNotHasKey('identifier:\Backend\NotAvailable', $availableBackends);
+ }
+
+ public function testGetUserBackends() {
+ $service = new BackendService($this->config, $this->l10n);
+
+ $backendAllowed = $this->getBackendMock('\User\Mount\Allowed');
+ $backendAllowed->expects($this->once())
+ ->method('isVisibleFor')
+ ->with(BackendService::VISIBILITY_PERSONAL)
+ ->will($this->returnValue(true));
+ $backendNotAllowed = $this->getBackendMock('\User\Mount\NotAllowed');
+ $backendNotAllowed->expects($this->once())
+ ->method('isVisibleFor')
+ ->with(BackendService::VISIBILITY_PERSONAL)
+ ->will($this->returnValue(false));
+
+ $service->registerBackend($backendAllowed);
+ $service->registerBackend($backendNotAllowed);
+
+ $userBackends = $service->getBackendsVisibleFor(BackendService::VISIBILITY_PERSONAL);
+ $this->assertArrayHasKey('identifier:\User\Mount\Allowed', $userBackends);
+ $this->assertArrayNotHasKey('identifier:\User\Mount\NotAllowed', $userBackends);
+ }
+
+}
+
diff --git a/apps/files_external/tests/service/globalstoragesservicetest.php b/apps/files_external/tests/service/globalstoragesservicetest.php
index ac25f58b1d1..05585d2c065 100644
--- a/apps/files_external/tests/service/globalstoragesservicetest.php
+++ b/apps/files_external/tests/service/globalstoragesservicetest.php
@@ -29,7 +29,7 @@ use \OCA\Files_external\Lib\StorageConfig;
class GlobalStoragesServiceTest extends StoragesServiceTest {
public function setUp() {
parent::setUp();
- $this->service = new GlobalStoragesService();
+ $this->service = new GlobalStoragesService($this->backendService);
}
public function tearDown() {
@@ -40,7 +40,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
protected function makeTestStorageData() {
return $this->makeStorageConfig([
'mountPoint' => 'mountpoint',
- 'backendClass' => '\OC\Files\Storage\SMB',
+ 'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
+ 'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@@ -59,9 +60,10 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
return [
// all users
[
- $this->makeStorageConfig([
+ [
'mountPoint' => 'mountpoint',
- 'backendClass' => '\OC\Files\Storage\SMB',
+ 'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
+ 'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@@ -70,13 +72,14 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
'applicableUsers' => [],
'applicableGroups' => [],
'priority' => 15,
- ]),
+ ],
],
// some users
[
- $this->makeStorageConfig([
+ [
'mountPoint' => 'mountpoint',
- 'backendClass' => '\OC\Files\Storage\SMB',
+ 'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
+ 'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@@ -85,13 +88,14 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
'applicableUsers' => ['user1', 'user2'],
'applicableGroups' => [],
'priority' => 15,
- ]),
+ ],
],
// some groups
[
- $this->makeStorageConfig([
+ [
'mountPoint' => 'mountpoint',
- 'backendClass' => '\OC\Files\Storage\SMB',
+ 'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
+ 'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@@ -100,13 +104,14 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
'applicableUsers' => [],
'applicableGroups' => ['group1', 'group2'],
'priority' => 15,
- ]),
+ ],
],
// both users and groups
[
- $this->makeStorageConfig([
+ [
'mountPoint' => 'mountpoint',
- 'backendClass' => '\OC\Files\Storage\SMB',
+ 'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
+ 'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@@ -115,7 +120,7 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
'applicableUsers' => ['user1', 'user2'],
'applicableGroups' => ['group1', 'group2'],
'priority' => 15,
- ]),
+ ],
],
];
}
@@ -123,7 +128,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
/**
* @dataProvider storageDataProvider
*/
- public function testAddStorage($storage) {
+ public function testAddStorage($storageParams) {
+ $storage = $this->makeStorageConfig($storageParams);
$newStorage = $this->service->addStorage($storage);
$this->assertEquals(1, $newStorage->getId());
@@ -132,7 +138,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$newStorage = $this->service->getStorage(1);
$this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint());
- $this->assertEquals($storage->getBackendClass(), $newStorage->getBackendClass());
+ $this->assertEquals($storage->getBackend(), $newStorage->getBackend());
+ $this->assertEquals($storage->getAuthMechanism(), $newStorage->getAuthMechanism());
$this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions());
$this->assertEquals($storage->getApplicableUsers(), $newStorage->getApplicableUsers());
$this->assertEquals($storage->getApplicableGroups(), $newStorage->getApplicableGroups());
@@ -148,10 +155,12 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
/**
* @dataProvider storageDataProvider
*/
- public function testUpdateStorage($updatedStorage) {
+ public function testUpdateStorage($updatedStorageParams) {
+ $updatedStorage = $this->makeStorageConfig($updatedStorageParams);
$storage = $this->makeStorageConfig([
'mountPoint' => 'mountpoint',
- 'backendClass' => '\OC\Files\Storage\SMB',
+ 'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
+ 'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@@ -638,7 +647,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$mountPointOptions = current($mountPointData);
$this->assertEquals(1, $mountPointOptions['id']);
- $this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']);
+ $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SMB', $mountPointOptions['backend']);
+ $this->assertEquals('identifier:\Auth\Mechanism', $mountPointOptions['authMechanism']);
$this->assertEquals(15, $mountPointOptions['priority']);
$this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
@@ -678,7 +688,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$mountPointOptions = current($mountPointData);
$this->assertEquals(1, $mountPointOptions['id']);
- $this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']);
+ $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SMB', $mountPointOptions['backend']);
+ $this->assertEquals('identifier:\Auth\Mechanism', $mountPointOptions['authMechanism']);
$this->assertEquals(15, $mountPointOptions['priority']);
$this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
@@ -695,7 +706,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$mountPointOptions = current($mountPointData);
$this->assertEquals(1, $mountPointOptions['id']);
- $this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']);
+ $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SMB', $mountPointOptions['backend']);
+ $this->assertEquals('identifier:\Auth\Mechanism', $mountPointOptions['authMechanism']);
$this->assertEquals(15, $mountPointOptions['priority']);
$this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
@@ -720,13 +732,15 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$legacyBackendOptions = \OC_Mount_Config::encryptPasswords($legacyBackendOptions);
$legacyConfig = [
- 'class' => '\OC\Files\Storage\SMB',
+ 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
+ 'authMechanism' => 'identifier:\Auth\Mechanism',
'options' => $legacyBackendOptions,
'mountOptions' => ['preview' => false],
];
// different mount options
$legacyConfig2 = [
- 'class' => '\OC\Files\Storage\SMB',
+ 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
+ 'authMechanism' => 'identifier:\Auth\Mechanism',
'options' => $legacyBackendOptions,
'mountOptions' => ['preview' => true],
];
@@ -737,7 +751,8 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
// different config
$legacyConfig3 = [
- 'class' => '\OC\Files\Storage\SMB',
+ 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
+ 'authMechanism' => 'identifier:\Auth\Mechanism',
'options' => $legacyBackendOptions2,
'mountOptions' => ['preview' => true],
];
@@ -811,4 +826,85 @@ class GlobalStoragesServiceTest extends StoragesServiceTest {
$this->assertEquals([], $storage4->getApplicableGroups());
$this->assertEquals(['preview' => true], $storage4->getMountOptions());
}
+
+ public function testReadLegacyConfigNoAuthMechanism() {
+ $configFile = $this->dataDir . '/mount.json';
+
+ $json = [
+ 'user' => [
+ 'user1' => [
+ '/$user/files/somemount' => [
+ 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SFTP',
+ 'authMechanism' => 'identifier:\Auth\Mechanism',
+ 'options' => [],
+ 'mountOptions' => [],
+ ],
+ '/$user/files/othermount' => [
+ 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SFTP',
+ // no authMechanism
+ 'options' => [],
+ 'mountOptions' => [],
+ ],
+ ]
+ ]
+ ];
+
+ file_put_contents($configFile, json_encode($json));
+
+ $allStorages = $this->service->getAllStorages();
+
+ $this->assertCount(2, $allStorages);
+
+ $storage1 = $allStorages[1];
+ $storage2 = $allStorages[2];
+
+ $this->assertEquals('/somemount', $storage1->getMountPoint());
+ $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SFTP', $storage1->getBackend()->getIdentifier());
+ $this->assertEquals('identifier:\Auth\Mechanism', $storage1->getAuthMechanism()->getIdentifier());
+
+ $this->assertEquals('/othermount', $storage2->getMountPoint());
+ $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SFTP', $storage2->getBackend()->getIdentifier());
+ $this->assertEquals('identifier:\Other\Auth\Mechanism', $storage2->getAuthMechanism()->getIdentifier());
+ }
+
+ public function testReadLegacyConfigClass() {
+ $configFile = $this->dataDir . '/mount.json';
+
+ $json = [
+ 'user' => [
+ 'user1' => [
+ '/$user/files/somemount' => [
+ 'class' => 'identifier:\OCA\Files_External\Lib\Backend\SFTP',
+ 'authMechanism' => 'identifier:\Auth\Mechanism',
+ 'options' => [],
+ 'mountOptions' => [],
+ ],
+ '/$user/files/othermount' => [
+ 'class' => 'identifier:sftp_alias',
+ 'authMechanism' => 'identifier:\Auth\Mechanism',
+ 'options' => [],
+ 'mountOptions' => [],
+ ],
+ ]
+ ]
+ ];
+
+ file_put_contents($configFile, json_encode($json));
+
+ $allStorages = $this->service->getAllStorages();
+
+ $this->assertCount(2, $allStorages);
+
+ $storage1 = $allStorages[1];
+ $storage2 = $allStorages[2];
+
+ $this->assertEquals('/somemount', $storage1->getMountPoint());
+ $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SFTP', $storage1->getBackend()->getIdentifier());
+ $this->assertEquals('identifier:\Auth\Mechanism', $storage1->getAuthMechanism()->getIdentifier());
+
+ $this->assertEquals('/othermount', $storage2->getMountPoint());
+ $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SFTP', $storage2->getBackend()->getIdentifier());
+ $this->assertEquals('identifier:\Auth\Mechanism', $storage2->getAuthMechanism()->getIdentifier());
+ }
+
}
diff --git a/apps/files_external/tests/service/storagesservicetest.php b/apps/files_external/tests/service/storagesservicetest.php
index 36f68a83b11..28220c9bc2e 100644
--- a/apps/files_external/tests/service/storagesservicetest.php
+++ b/apps/files_external/tests/service/storagesservicetest.php
@@ -1,6 +1,7 @@
<?php
/**
* @author Vincent Petry <pvince81@owncloud.com>
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
@@ -24,6 +25,7 @@ use \OC\Files\Filesystem;
use \OCA\Files_external\NotFoundException;
use \OCA\Files_external\Lib\StorageConfig;
+use \OCA\Files_External\Lib\BackendService;
abstract class StoragesServiceTest extends \Test\TestCase {
@@ -32,6 +34,9 @@ abstract class StoragesServiceTest extends \Test\TestCase {
*/
protected $service;
+ /** @var BackendService */
+ protected $backendService;
+
/**
* Data directory
*
@@ -55,6 +60,51 @@ abstract class StoragesServiceTest extends \Test\TestCase {
);
\OC_Mount_Config::$skipTest = true;
+ // prepare BackendService mock
+ $this->backendService =
+ $this->getMockBuilder('\OCA\Files_External\Service\BackendService')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $authMechanisms = [
+ 'identifier:\Auth\Mechanism' => $this->getAuthMechMock('null', '\Auth\Mechanism'),
+ 'identifier:\Other\Auth\Mechanism' => $this->getAuthMechMock('null', '\Other\Auth\Mechanism'),
+ 'identifier:\OCA\Files_External\Lib\Auth\NullMechanism' => $this->getAuthMechMock(),
+ ];
+ $this->backendService->method('getAuthMechanism')
+ ->will($this->returnCallback(function($class) use ($authMechanisms) {
+ if (isset($authMechanisms[$class])) {
+ return $authMechanisms[$class];
+ }
+ return null;
+ }));
+ $this->backendService->method('getAuthMechanismsByScheme')
+ ->will($this->returnCallback(function($schemes) use ($authMechanisms) {
+ return array_filter($authMechanisms, function ($authMech) use ($schemes) {
+ return in_array($authMech->getScheme(), $schemes, true);
+ });
+ }));
+ $this->backendService->method('getAuthMechanisms')
+ ->will($this->returnValue($authMechanisms));
+
+ $sftpBackend = $this->getBackendMock('\OCA\Files_External\Lib\Backend\SFTP', '\OC\Files\Storage\SFTP');
+ $backends = [
+ 'identifier:\OCA\Files_External\Lib\Backend\SMB' => $this->getBackendMock('\OCA\Files_External\Lib\Backend\SMB', '\OC\Files\Storage\SMB'),
+ 'identifier:\OCA\Files_External\Lib\Backend\SFTP' => $sftpBackend,
+ 'identifier:sftp_alias' => $sftpBackend,
+ ];
+ $backends['identifier:\OCA\Files_External\Lib\Backend\SFTP']->method('getLegacyAuthMechanism')
+ ->willReturn($authMechanisms['identifier:\Other\Auth\Mechanism']);
+ $this->backendService->method('getBackend')
+ ->will($this->returnCallback(function($backendClass) use ($backends) {
+ if (isset($backends[$backendClass])) {
+ return $backends[$backendClass];
+ }
+ return null;
+ }));
+ $this->backendService->method('getBackends')
+ ->will($this->returnValue($backends));
+
\OCP\Util::connectHook(
Filesystem::CLASSNAME,
Filesystem::signal_create_mount,
@@ -64,6 +114,19 @@ abstract class StoragesServiceTest extends \Test\TestCase {
Filesystem::signal_delete_mount,
get_class($this), 'deleteHookCallback');
+ $containerMock = $this->getMock('\OCP\AppFramework\IAppContainer');
+ $containerMock->method('query')
+ ->will($this->returnCallback(function($name) {
+ if ($name === 'OCA\Files_External\Service\BackendService') {
+ return $this->backendService;
+ }
+ }));
+
+ \OC_Mount_Config::$app = $this->getMockBuilder('\OCA\Files_External\Appinfo\Application')
+ ->disableOriginalConstructor()
+ ->getMock();
+ \OC_Mount_Config::$app->method('getContainer')
+ ->willReturn($containerMock);
}
public function tearDown() {
@@ -71,6 +134,29 @@ abstract class StoragesServiceTest extends \Test\TestCase {
self::$hookCalls = array();
}
+ protected function getBackendMock($class = '\OCA\Files_External\Lib\Backend\SMB', $storageClass = '\OC\Files\Storage\SMB') {
+ $backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $backend->method('getStorageClass')
+ ->willReturn($storageClass);
+ $backend->method('getIdentifier')
+ ->willReturn('identifier:'.$class);
+ return $backend;
+ }
+
+ protected function getAuthMechMock($scheme = 'null', $class = '\OCA\Files_External\Lib\Auth\NullMechanism') {
+ $authMech = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $authMech->method('getScheme')
+ ->willReturn($scheme);
+ $authMech->method('getIdentifier')
+ ->willReturn('identifier:'.$class);
+
+ return $authMech;
+ }
+
/**
* Creates a StorageConfig instance based on array data
*
@@ -84,7 +170,22 @@ abstract class StoragesServiceTest extends \Test\TestCase {
$storage->setId($data['id']);
}
$storage->setMountPoint($data['mountPoint']);
- $storage->setBackendClass($data['backendClass']);
+ if (!isset($data['backend'])) {
+ // data providers are run before $this->backendService is initialised
+ // so $data['backend'] can be specified directly
+ $data['backend'] = $this->backendService->getBackend($data['backendIdentifier']);
+ }
+ if (!isset($data['backend'])) {
+ throw new \Exception('oops, no backend');
+ }
+ if (!isset($data['authMechanism'])) {
+ $data['authMechanism'] = $this->backendService->getAuthMechanism($data['authMechanismIdentifier']);
+ }
+ if (!isset($data['authMechanism'])) {
+ throw new \Exception('oops, no auth mechanism');
+ }
+ $storage->setBackend($data['backend']);
+ $storage->setAuthMechanism($data['authMechanism']);
$storage->setBackendOptions($data['backendOptions']);
if (isset($data['applicableUsers'])) {
$storage->setApplicableUsers($data['applicableUsers']);
@@ -106,16 +207,22 @@ abstract class StoragesServiceTest extends \Test\TestCase {
* @expectedException \OCA\Files_external\NotFoundException
*/
public function testNonExistingStorage() {
+ $backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
+ $authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
$storage = new StorageConfig(255);
$storage->setMountPoint('mountpoint');
- $storage->setBackendClass('\OC\Files\Storage\SMB');
+ $storage->setBackend($backend);
+ $storage->setAuthMechanism($authMechanism);
$this->service->updateStorage($storage);
}
public function testDeleteStorage() {
+ $backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
+ $authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
$storage = new StorageConfig(255);
$storage->setMountPoint('mountpoint');
- $storage->setBackendClass('\OC\Files\Storage\SMB');
+ $storage->setBackend($backend);
+ $storage->setAuthMechanism($authMechanism);
$storage->setBackendOptions(['password' => 'testPassword']);
$newStorage = $this->service->addStorage($storage);
@@ -140,6 +247,64 @@ abstract class StoragesServiceTest extends \Test\TestCase {
$this->service->removeStorage(255);
}
+ public function testCreateStorage() {
+ $mountPoint = 'mount';
+ $backendIdentifier = 'identifier:\OCA\Files_External\Lib\Backend\SMB';
+ $authMechanismIdentifier = 'identifier:\Auth\Mechanism';
+ $backendOptions = ['param' => 'foo', 'param2' => 'bar'];
+ $mountOptions = ['option' => 'foobar'];
+ $applicableUsers = ['user1', 'user2'];
+ $applicableGroups = ['group'];
+ $priority = 123;
+
+ $backend = $this->backendService->getBackend($backendIdentifier);
+ $authMechanism = $this->backendService->getAuthMechanism($authMechanismIdentifier);
+
+ $storage = $this->service->createStorage(
+ $mountPoint,
+ $backendIdentifier,
+ $authMechanismIdentifier,
+ $backendOptions,
+ $mountOptions,
+ $applicableUsers,
+ $applicableGroups,
+ $priority
+ );
+
+ $this->assertEquals('/'.$mountPoint, $storage->getMountPoint());
+ $this->assertEquals($backend, $storage->getBackend());
+ $this->assertEquals($authMechanism, $storage->getAuthMechanism());
+ $this->assertEquals($backendOptions, $storage->getBackendOptions());
+ $this->assertEquals($mountOptions, $storage->getMountOptions());
+ $this->assertEquals($applicableUsers, $storage->getApplicableUsers());
+ $this->assertEquals($applicableGroups, $storage->getApplicableGroups());
+ $this->assertEquals($priority, $storage->getPriority());
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testCreateStorageInvalidClass() {
+ $this->service->createStorage(
+ 'mount',
+ 'identifier:\OC\Not\A\Backend',
+ 'identifier:\Auth\Mechanism',
+ []
+ );
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testCreateStorageInvalidAuthMechanismClass() {
+ $this->service->createStorage(
+ 'mount',
+ 'identifier:\OCA\Files_External\Lib\Backend\SMB',
+ 'identifier:\Not\An\Auth\Mechanism',
+ []
+ );
+ }
+
public static function createHookCallback($params) {
self::$hookCalls[] = array(
'signal' => Filesystem::signal_create_mount,
diff --git a/apps/files_external/tests/service/userglobalstoragesservicetest.php b/apps/files_external/tests/service/userglobalstoragesservicetest.php
new file mode 100644
index 00000000000..49a02453840
--- /dev/null
+++ b/apps/files_external/tests/service/userglobalstoragesservicetest.php
@@ -0,0 +1,215 @@
+<?php
+/**
+ * @author Robin McCorkell <rmccorkell@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\Files_External\Tests\Service;
+
+use \OCA\Files_External\Service\UserGlobalStoragesService;
+use \OCP\IGroupManager;
+
+use \OCA\Files_External\Lib\StorageConfig;
+
+class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest {
+
+ protected $groupManager;
+
+ protected $globalStoragesService;
+
+ protected $user;
+
+ const USER_ID = 'test_user';
+ const GROUP_ID = 'test_group';
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->globalStoragesService = $this->service;
+
+ $this->user = new \OC\User\User(self::USER_ID, null);
+ $userSession = $this->getMock('\OCP\IUserSession');
+ $userSession
+ ->expects($this->any())
+ ->method('getUser')
+ ->will($this->returnValue($this->user));
+
+ $this->groupManager = $this->getMock('\OCP\IGroupManager');
+ $this->groupManager->method('isInGroup')
+ ->will($this->returnCallback(function($userId, $groupId) {
+ if ($userId === self::USER_ID && $groupId === self::GROUP_ID) {
+ return true;
+ }
+ return false;
+ }));
+
+ $this->service = new UserGlobalStoragesService(
+ $this->backendService,
+ $userSession,
+ $this->groupManager
+ );
+ }
+
+ public function applicableStorageProvider() {
+ return [
+ [[], [], true],
+
+ // not applicable cases
+ [['user1'], [], false],
+ [[], ['group1'], false],
+ [['user1'], ['group1'], false],
+
+ // applicable cases
+ [[self::USER_ID], [], true],
+ [[], [self::GROUP_ID], true],
+ [[self::USER_ID], ['group1'], true],
+ [['user1'], [self::GROUP_ID], true],
+
+ // sanity checks
+ [['user1', 'user2', self::USER_ID, 'user3'], [], true],
+ ];
+ }
+
+ /**
+ * @dataProvider applicableStorageProvider
+ */
+ public function testGetStorageWithApplicable($applicableUsers, $applicableGroups, $isVisible) {
+ $backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
+ $authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
+
+ $storage = new StorageConfig();
+ $storage->setMountPoint('mountpoint');
+ $storage->setBackend($backend);
+ $storage->setAuthMechanism($authMechanism);
+ $storage->setBackendOptions(['password' => 'testPassword']);
+ $storage->setApplicableUsers($applicableUsers);
+ $storage->setApplicableGroups($applicableGroups);
+
+ $newStorage = $this->globalStoragesService->addStorage($storage);
+
+ $storages = $this->service->getAllStorages();
+ if ($isVisible) {
+ $this->assertEquals(1, count($storages));
+ $retrievedStorage = $this->service->getStorage($newStorage->getId());
+ $this->assertEquals('/mountpoint', $retrievedStorage->getMountPoint());
+ } else {
+ $this->assertEquals(0, count($storages));
+ }
+
+ }
+
+ /**
+ * @expectedException \DomainException
+ */
+ public function testAddStorage($storageParams = null) {
+ $backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
+ $authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
+
+ $storage = new StorageConfig(255);
+ $storage->setMountPoint('mountpoint');
+ $storage->setBackend($backend);
+ $storage->setAuthMechanism($authMechanism);
+ $storage->setBackendOptions(['password' => 'testPassword']);
+
+ $this->service->addStorage($storage);
+ }
+
+ /**
+ * @expectedException \DomainException
+ */
+ public function testUpdateStorage($storageParams = null) {
+ $backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
+ $authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
+
+ $storage = new StorageConfig(255);
+ $storage->setMountPoint('mountpoint');
+ $storage->setBackend($backend);
+ $storage->setAuthMechanism($authMechanism);
+ $storage->setBackendOptions(['password' => 'testPassword']);
+
+ $newStorage = $this->globalStoragesService->addStorage($storage);
+
+ $retrievedStorage = $this->service->getStorage($newStorage->getId());
+ $retrievedStorage->setMountPoint('abc');
+ $this->service->updateStorage($retrievedStorage);
+ }
+
+ /**
+ * @expectedException \DomainException
+ */
+ public function testDeleteStorage() {
+ $backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
+ $authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
+
+ $storage = new StorageConfig(255);
+ $storage->setMountPoint('mountpoint');
+ $storage->setBackend($backend);
+ $storage->setAuthMechanism($authMechanism);
+ $storage->setBackendOptions(['password' => 'testPassword']);
+
+ $newStorage = $this->globalStoragesService->addStorage($storage);
+ $this->assertEquals(1, $newStorage->getId());
+
+ $this->service->removeStorage(1);
+ }
+
+ public function testHooksAddStorage($a = null, $b = null, $c = null) {
+ // we don't test this here
+ $this->assertTrue(true);
+ }
+
+ public function testHooksUpdateStorage($a = null, $b = null, $c = null, $d = null, $e = null) {
+ // we don't test this here
+ $this->assertTrue(true);
+ }
+
+ public function testHooksRenameMountPoint() {
+ // we don't test this here
+ $this->assertTrue(true);
+ }
+
+ public function testHooksDeleteStorage($a = null, $b = null, $c = null) {
+ // we don't test this here
+ $this->assertTrue(true);
+ }
+
+ public function testLegacyConfigConversionApplicableAll() {
+ // we don't test this here
+ $this->assertTrue(true);
+ }
+
+ public function testLegacyConfigConversionApplicableUserAndGroup() {
+ // we don't test this here
+ $this->assertTrue(true);
+ }
+
+ public function testReadLegacyConfigAndGenerateConfigId() {
+ // we don't test this here
+ $this->assertTrue(true);
+ }
+
+ public function testReadLegacyConfigNoAuthMechanism() {
+ // we don't test this here
+ $this->assertTrue(true);
+ }
+
+ public function testReadLegacyConfigClass() {
+ // we don't test this here
+ $this->assertTrue(true);
+ }
+
+}
diff --git a/apps/files_external/tests/service/userstoragesservicetest.php b/apps/files_external/tests/service/userstoragesservicetest.php
index ab102741ee2..0d5b82e2f8c 100644
--- a/apps/files_external/tests/service/userstoragesservicetest.php
+++ b/apps/files_external/tests/service/userstoragesservicetest.php
@@ -40,7 +40,7 @@ class UserStoragesServiceTest extends StoragesServiceTest {
->method('getUser')
->will($this->returnValue($this->user));
- $this->service = new UserStoragesService($userSession);
+ $this->service = new UserStoragesService($this->backendService, $userSession);
// create home folder
mkdir($this->dataDir . '/' . $this->userId . '/');
@@ -54,7 +54,8 @@ class UserStoragesServiceTest extends StoragesServiceTest {
private function makeTestStorageData() {
return $this->makeStorageConfig([
'mountPoint' => 'mountpoint',
- 'backendClass' => '\OC\Files\Storage\SMB',
+ 'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
+ 'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@@ -76,7 +77,8 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$newStorage = $this->service->getStorage(1);
$this->assertEquals($storage->getMountPoint(), $newStorage->getMountPoint());
- $this->assertEquals($storage->getBackendClass(), $newStorage->getBackendClass());
+ $this->assertEquals($storage->getBackend(), $newStorage->getBackend());
+ $this->assertEquals($storage->getAuthMechanism(), $newStorage->getAuthMechanism());
$this->assertEquals($storage->getBackendOptions(), $newStorage->getBackendOptions());
$this->assertEquals(1, $newStorage->getId());
$this->assertEquals(0, $newStorage->getStatus());
@@ -98,7 +100,8 @@ class UserStoragesServiceTest extends StoragesServiceTest {
public function testUpdateStorage() {
$storage = $this->makeStorageConfig([
'mountPoint' => 'mountpoint',
- 'backendClass' => '\OC\Files\Storage\SMB',
+ 'backendIdentifier' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
+ 'authMechanismIdentifier' => 'identifier:\Auth\Mechanism',
'backendOptions' => [
'option1' => 'value1',
'option2' => 'value2',
@@ -191,7 +194,8 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$mountPointOptions = current($mountPointData);
$this->assertEquals(1, $mountPointOptions['id']);
- $this->assertEquals('\OC\Files\Storage\SMB', $mountPointOptions['class']);
+ $this->assertEquals('identifier:\OCA\Files_External\Lib\Backend\SMB', $mountPointOptions['backend']);
+ $this->assertEquals('identifier:\Auth\Mechanism', $mountPointOptions['authMechanism']);
$this->assertEquals(false, $mountPointOptions['mountOptions']['preview']);
$backendOptions = $mountPointOptions['options'];
@@ -214,13 +218,15 @@ class UserStoragesServiceTest extends StoragesServiceTest {
$legacyBackendOptions = \OC_Mount_Config::encryptPasswords($legacyBackendOptions);
$legacyConfig = [
- 'class' => '\OC\Files\Storage\SMB',
+ 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
+ 'authMechanism' => 'identifier:\Auth\Mechanism',
'options' => $legacyBackendOptions,
'mountOptions' => ['preview' => false],
];
// different mount options
$legacyConfig2 = [
- 'class' => '\OC\Files\Storage\SMB',
+ 'backend' => 'identifier:\OCA\Files_External\Lib\Backend\SMB',
+ 'authMechanism' => 'identifier:\Auth\Mechanism',
'options' => $legacyBackendOptions,
'mountOptions' => ['preview' => true],
];
diff --git a/apps/files_external/tests/storageconfigtest.php b/apps/files_external/tests/storageconfigtest.php
index c30a4935ce1..dba5105d7db 100644
--- a/apps/files_external/tests/storageconfigtest.php
+++ b/apps/files_external/tests/storageconfigtest.php
@@ -26,9 +26,22 @@ use \OCA\Files_external\Lib\StorageConfig;
class StorageConfigTest extends \Test\TestCase {
public function testJsonSerialization() {
+ $backend = $this->getMockBuilder('\OCA\Files_External\Lib\Backend\Backend')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $backend->method('getIdentifier')
+ ->willReturn('storage::identifier');
+
+ $authMech = $this->getMockBuilder('\OCA\Files_External\Lib\Auth\AuthMechanism')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $authMech->method('getIdentifier')
+ ->willReturn('auth::identifier');
+
$storageConfig = new StorageConfig(1);
$storageConfig->setMountPoint('test');
- $storageConfig->setBackendClass('\OC\Files\Storage\SMB');
+ $storageConfig->setBackend($backend);
+ $storageConfig->setAuthMechanism($authMech);
$storageConfig->setBackendOptions(['user' => 'test', 'password' => 'password123']);
$storageConfig->setPriority(128);
$storageConfig->setApplicableUsers(['user1', 'user2']);
@@ -39,7 +52,8 @@ class StorageConfigTest extends \Test\TestCase {
$this->assertEquals(1, $json['id']);
$this->assertEquals('/test', $json['mountPoint']);
- $this->assertEquals('\OC\Files\Storage\SMB', $json['backendClass']);
+ $this->assertEquals('storage::identifier', $json['backend']);
+ $this->assertEquals('auth::identifier', $json['authMechanism']);
$this->assertEquals('test', $json['backendOptions']['user']);
$this->assertEquals('password123', $json['backendOptions']['password']);
$this->assertEquals(128, $json['priority']);
diff --git a/apps/files_sharing/api/server2server.php b/apps/files_sharing/api/server2server.php
index 8bda0bb8749..211dc52c333 100644
--- a/apps/files_sharing/api/server2server.php
+++ b/apps/files_sharing/api/server2server.php
@@ -51,6 +51,14 @@ class Server2Server {
return new \OC_OCS_Result(null, 400, 'The mountpoint name contains invalid characters.');
}
+ \OCP\Util::writeLog('files_sharing', 'shareWith before, ' . $shareWith, \OCP\Util::DEBUG);
+ \OCP\Util::emitHook(
+ '\OCA\Files_Sharing\API\Server2Server',
+ 'preLoginNameUsedAsUserName',
+ array('uid' => &$shareWith)
+ );
+ \OCP\Util::writeLog('files_sharing', 'shareWith after, ' . $shareWith, \OCP\Util::DEBUG);
+
if (!\OCP\User::userExists($shareWith)) {
return new \OC_OCS_Result(null, 400, 'User does not exists');
}
diff --git a/apps/files_sharing/lib/share/folder.php b/apps/files_sharing/lib/share/folder.php
index e18839b577d..ef42393f58d 100644
--- a/apps/files_sharing/lib/share/folder.php
+++ b/apps/files_sharing/lib/share/folder.php
@@ -39,7 +39,7 @@ class OC_Share_Backend_Folder extends OC_Share_Backend_File implements OCP\Share
$shares = \OCP\Share::getItemSharedWithUser('folder', $parent, $shareWith, $owner);
if ($shares) {
foreach ($shares as $share) {
- $name = substr($share['path'], strrpos($share['path'], '/') + 1);
+ $name = basename($share['path']);
$share['collection']['path'] = $name;
$share['collection']['item_type'] = 'folder';
$share['file_path'] = $name;
diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php
index 2962f62520d..43c76125e16 100644
--- a/apps/files_sharing/templates/public.php
+++ b/apps/files_sharing/templates/public.php
@@ -16,6 +16,7 @@ OCP\Util::addStyle('files', 'files');
OCP\Util::addStyle('files', 'upload');
OCP\Util::addScript('files', 'filesummary');
OCP\Util::addScript('files', 'breadcrumb');
+OCP\Util::addScript('files', 'fileinfomodel');
OCP\Util::addScript('files', 'files');
OCP\Util::addScript('files', 'filelist');
OCP\Util::addscript('files', 'keyboardshortcuts');
diff --git a/apps/user_ldap/appinfo/app.php b/apps/user_ldap/appinfo/app.php
index 5457e6b654f..68fd1b698e0 100644
--- a/apps/user_ldap/appinfo/app.php
+++ b/apps/user_ldap/appinfo/app.php
@@ -62,6 +62,13 @@ if(count($configPrefixes) > 0) {
OCP\Backgroundjob::registerJob('OCA\user_ldap\lib\Jobs');
OCP\Backgroundjob::registerJob('\OCA\User_LDAP\Jobs\CleanUp');
+\OCP\Util::connectHook(
+ '\OCA\Files_Sharing\API\Server2Server',
+ 'preLoginNameUsedAsUserName',
+ '\OCA\user_ldap\lib\Helper',
+ 'loginName2UserName'
+);
+
if(OCP\App::isEnabled('user_webdavauth')) {
OCP\Util::writeLog('user_ldap',
'user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour',
diff --git a/apps/user_ldap/lib/helper.php b/apps/user_ldap/lib/helper.php
index 40874b2ef9f..57b75823a1d 100644
--- a/apps/user_ldap/lib/helper.php
+++ b/apps/user_ldap/lib/helper.php
@@ -27,6 +27,9 @@
namespace OCA\user_ldap\lib;
+use OCA\user_ldap\lib\LDAP;
+use OCA\user_ldap\User_Proxy;
+
class Helper {
/**
@@ -181,4 +184,32 @@ class Helper {
return $domain;
}
+
+ /**
+ * listens to a hook thrown by server2server sharing and replaces the given
+ * login name by a username, if it matches an LDAP user.
+ *
+ * @param array $param
+ * @throws \Exception
+ */
+ public static function loginName2UserName($param) {
+ if(!isset($param['uid'])) {
+ throw new \Exception('key uid is expected to be set in $param');
+ }
+
+ //ain't it ironic?
+ $helper = new Helper();
+
+ $configPrefixes = $helper->getServerConfigurationPrefixes(true);
+ $ldapWrapper = new LDAP();
+ $ocConfig = \OC::$server->getConfig();
+
+ $userBackend = new User_Proxy(
+ $configPrefixes, $ldapWrapper, $ocConfig
+ );
+ $uid = $userBackend->loginName2UserName($param['uid'] );
+ if($uid !== false) {
+ $param['uid'] = $uid;
+ }
+ }
}
diff --git a/apps/user_ldap/user_ldap.php b/apps/user_ldap/user_ldap.php
index a2f4b4ee9e5..00cba718369 100644
--- a/apps/user_ldap/user_ldap.php
+++ b/apps/user_ldap/user_ldap.php
@@ -71,6 +71,43 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
}
/**
+ * returns the username for the given login name, if available
+ *
+ * @param string $loginName
+ * @return string|false
+ */
+ public function loginName2UserName($loginName) {
+ try {
+ $ldapRecord = $this->getLDAPUserByLoginName($loginName);
+ $user = $this->access->userManager->get($ldapRecord['dn']);
+ if($user instanceof OfflineUser) {
+ return false;
+ }
+ return $user->getUsername();
+ } catch (\Exception $e) {
+ return false;
+ }
+ }
+
+ /**
+ * returns an LDAP record based on a given login name
+ *
+ * @param string $loginName
+ * @return array
+ * @throws \Exception
+ */
+ public function getLDAPUserByLoginName($loginName) {
+ //find out dn of the user name
+ $attrs = array($this->access->connection->ldapUserDisplayName, 'dn',
+ 'uid', 'samaccountname');
+ $users = $this->access->fetchUsersByLoginName($loginName, $attrs);
+ if(count($users) < 1) {
+ throw new \Exception('No user available for the given login name.');
+ }
+ return $users[0];
+ }
+
+ /**
* Check if the password is correct
* @param string $uid The username
* @param string $password The password
@@ -79,15 +116,14 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
* Check if the password is correct without logging in the user
*/
public function checkPassword($uid, $password) {
- //find out dn of the user name
- $attrs = array($this->access->connection->ldapUserDisplayName, 'dn',
- 'uid', 'samaccountname');
- $users = $this->access->fetchUsersByLoginName($uid, $attrs);
- if(count($users) < 1) {
+ try {
+ $ldapRecord = $this->getLDAPUserByLoginName($uid);
+ } catch(\Exception $e) {
return false;
}
- $dn = $users[0]['dn'];
+ $dn = $ldapRecord['dn'];
$user = $this->access->userManager->get($dn);
+
if(!$user instanceof User) {
\OCP\Util::writeLog('user_ldap',
'LDAP Login: Could not get user object for DN ' . $dn .
@@ -102,14 +138,14 @@ class USER_LDAP extends BackendUtility implements \OCP\IUserBackend, \OCP\UserIn
}
$user->markLogin();
- if(isset($users[0][$this->access->connection->ldapUserDisplayName])) {
- $dpn = $users[0][$this->access->connection->ldapUserDisplayName];
+ if(isset($ldapRecord[$this->access->connection->ldapUserDisplayName])) {
+ $dpn = $ldapRecord[$this->access->connection->ldapUserDisplayName];
$user->storeDisplayName($dpn);
}
- if(isset($users[0]['uid'])) {
- $user->storeLDAPUserName($users[0]['uid']);
- } else if(isset($users[0]['samaccountname'])) {
- $user->storeLDAPUserName($users[0]['samaccountname']);
+ if(isset($ldapRecord['uid'])) {
+ $user->storeLDAPUserName($ldapRecord['uid']);
+ } else if(isset($ldapRecord['samaccountname'])) {
+ $user->storeLDAPUserName($ldapRecord['samaccountname']);
}
return $user->getUsername();
diff --git a/apps/user_ldap/user_proxy.php b/apps/user_ldap/user_proxy.php
index 683529eb902..1491be3f394 100644
--- a/apps/user_ldap/user_proxy.php
+++ b/apps/user_ldap/user_proxy.php
@@ -161,7 +161,7 @@ class User_Proxy extends lib\Proxy implements \OCP\IUserBackend, \OCP\UserInterf
/**
* check if a user exists on LDAP
- * @param string|OCA\User_LDAP\lib\User\User $user either the ownCloud user
+ * @param string|\OCA\User_LDAP\lib\User\User $user either the ownCloud user
* name or an instance of that user
* @return boolean
*/
@@ -183,6 +183,17 @@ class User_Proxy extends lib\Proxy implements \OCP\IUserBackend, \OCP\UserInterf
}
/**
+ * returns the username for the given login name, if available
+ *
+ * @param string $loginName
+ * @return string|false
+ */
+ public function loginName2UserName($loginName) {
+ $id = 'LOGINNAME,' . $loginName;
+ return $this->handleRequest($id, 'loginName2UserName', array($loginName));
+ }
+
+ /**
* get the user's home directory
* @param string $uid the username
* @return boolean