Allow setting user provided credentials from the personal settings page
This commit is contained in:
parent
f3e9729a5f
commit
860d51487b
|
@ -25,6 +25,7 @@ namespace OCA\Files_External\Controller;
|
|||
|
||||
|
||||
use \OCP\IConfig;
|
||||
use OCP\IUser;
|
||||
use \OCP\IUserSession;
|
||||
use \OCP\IRequest;
|
||||
use \OCP\IL10N;
|
||||
|
@ -114,6 +115,7 @@ abstract class StoragesController extends Controller {
|
|||
$priority
|
||||
);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
\OC::$server->getLogger()->logException($e);
|
||||
return new DataResponse(
|
||||
[
|
||||
'message' => (string)$this->l10n->t('Invalid backend or authentication mechanism class')
|
||||
|
|
|
@ -21,12 +21,19 @@
|
|||
|
||||
namespace OCA\Files_External\Controller;
|
||||
|
||||
use OCA\Calendar\Sabre\Backend;
|
||||
use OCA\Files_External\Lib\Auth\AuthMechanism;
|
||||
use OCA\Files_External\Lib\Auth\Password\UserProvided;
|
||||
use OCA\Files_external\Lib\StorageConfig;
|
||||
use OCA\Files_External\Service\UserGlobalStoragesService;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\IL10N;
|
||||
use OCP\IRequest;
|
||||
use OCP\IUserSession;
|
||||
|
||||
class UserCredentialsController extends Controller {
|
||||
class UserCredentialsController extends StoragesController {
|
||||
/**
|
||||
* @var UserProvided
|
||||
*/
|
||||
|
@ -37,10 +44,22 @@ class UserCredentialsController extends Controller {
|
|||
*/
|
||||
private $userSession;
|
||||
|
||||
public function __construct($appName, IRequest $request, UserProvided $authMechanism, IUserSession $userSession) {
|
||||
parent::__construct($appName, $request);
|
||||
/**
|
||||
* @var UserGlobalStoragesService
|
||||
*/
|
||||
private $globalStoragesService;
|
||||
|
||||
public function __construct(
|
||||
$appName, IRequest $request,
|
||||
UserProvided $authMechanism,
|
||||
IUserSession $userSession,
|
||||
IL10N $l10n,
|
||||
UserGlobalStoragesService $globalStoragesService
|
||||
) {
|
||||
parent::__construct($appName, $request, $l10n, $globalStoragesService);
|
||||
$this->authMechanism = $authMechanism;
|
||||
$this->userSession = $userSession;
|
||||
$this->globalStoragesService = $globalStoragesService;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -49,8 +68,32 @@ class UserCredentialsController extends Controller {
|
|||
* @param string $password
|
||||
*
|
||||
* @NoAdminRequired
|
||||
* @return DataResponse
|
||||
*/
|
||||
public function store($storageId, $username, $password) {
|
||||
$this->authMechanism->saveCredentials($this->userSession->getUser(), $storageId, $username, $password);
|
||||
|
||||
$storage = $this->globalStoragesService->getStorage($storageId);
|
||||
|
||||
$this->updateStorageStatus($storage);
|
||||
|
||||
$storage->setBackendOptions([]);
|
||||
$storage->setMountOptions([]);
|
||||
$this->manipulateStorageConfig($storage);
|
||||
|
||||
|
||||
return new DataResponse(
|
||||
$storage,
|
||||
Http::STATUS_OK
|
||||
);
|
||||
}
|
||||
|
||||
protected function manipulateStorageConfig(StorageConfig $storage) {
|
||||
/** @var AuthMechanism */
|
||||
$authMechanism = $storage->getAuthMechanism();
|
||||
$authMechanism->manipulateStorageConfig($storage, $this->userSession->getUser());
|
||||
/** @var Backend */
|
||||
$backend = $storage->getBackend();
|
||||
$backend->manipulateStorageConfig($storage, $this->userSession->getUser());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace OCA\Files_External\Controller;
|
|||
|
||||
use OCA\Files_External\Lib\Auth\AuthMechanism;
|
||||
use \OCP\IConfig;
|
||||
use OCP\IUser;
|
||||
use \OCP\IUserSession;
|
||||
use \OCP\IRequest;
|
||||
use \OCP\IL10N;
|
||||
|
|
|
@ -357,6 +357,9 @@ StorageConfig.prototype = {
|
|||
if (this.mountPoint === '') {
|
||||
return false;
|
||||
}
|
||||
if (!this.backend) {
|
||||
return false;
|
||||
}
|
||||
if (this.errors) {
|
||||
return false;
|
||||
}
|
||||
|
@ -432,6 +435,48 @@ UserStorageConfig.prototype = _.extend({}, StorageConfig.prototype,
|
|||
_url: 'apps/files_external/userstorages'
|
||||
});
|
||||
|
||||
/**
|
||||
* @class OCA.External.Settings.UserGlobalStorageConfig
|
||||
* @augments OCA.External.Settings.StorageConfig
|
||||
*
|
||||
* @classdesc User external storage config
|
||||
*/
|
||||
var UserGlobalStorageConfig = function (id) {
|
||||
this.id = id;
|
||||
};
|
||||
UserGlobalStorageConfig.prototype = _.extend({}, StorageConfig.prototype,
|
||||
/** @lends OCA.External.Settings.UserStorageConfig.prototype */ {
|
||||
|
||||
_url: 'apps/files_external/userglobalstorages',
|
||||
|
||||
/**
|
||||
* Creates or saves the storage.
|
||||
*
|
||||
* @param {Function} [options.success] success callback, receives result as argument
|
||||
* @param {Function} [options.error] error callback
|
||||
*/
|
||||
save: function (options) {
|
||||
var self = this;
|
||||
var url = OC.generateUrl('apps/files_external/usercredentials/{id}', {id: this.id});
|
||||
|
||||
$.ajax({
|
||||
type: 'PUT',
|
||||
url: url,
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({
|
||||
username: this.backendOptions.user,
|
||||
password: this.backendOptions.password
|
||||
}),
|
||||
success: function (result) {
|
||||
if (_.isFunction(options.success)) {
|
||||
options.success(result);
|
||||
}
|
||||
},
|
||||
error: options.error
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @class OCA.External.Settings.MountOptionsDropdown
|
||||
*
|
||||
|
@ -748,7 +793,7 @@ MountConfigListView.prototype = _.extend({
|
|||
|
||||
$.each(authMechanismConfiguration['configuration'], _.partial(
|
||||
this.writeParameterInput, $td, _, _, ['auth-param']
|
||||
));
|
||||
).bind(this));
|
||||
|
||||
this.trigger('selectAuthMechanism',
|
||||
$tr, authMechanism, authMechanismConfiguration['scheme'], onCompletion
|
||||
|
@ -770,6 +815,7 @@ MountConfigListView.prototype = _.extend({
|
|||
var $tr = this.$el.find('tr#addMountPoint');
|
||||
this.$el.find('tbody').append($tr.clone());
|
||||
|
||||
$tr.data('storageConfig', storageConfig);
|
||||
$tr.find('td').last().attr('class', 'remove');
|
||||
$tr.find('td.mountOptionsToggle').removeClass('hidden');
|
||||
$tr.find('td').last().removeAttr('style');
|
||||
|
@ -805,7 +851,7 @@ MountConfigListView.prototype = _.extend({
|
|||
$tr.find('td.authentication').append(selectAuthMechanism);
|
||||
|
||||
var $td = $tr.find('td.configuration');
|
||||
$.each(backend.configuration, _.partial(this.writeParameterInput, $td));
|
||||
$.each(backend.configuration, _.partial(this.writeParameterInput, $td).bind(this));
|
||||
|
||||
this.trigger('selectBackend', $tr, backend.identifier, onCompletion);
|
||||
this.configureAuthMechanism($tr, storageConfig.authMechanism, onCompletion);
|
||||
|
@ -866,8 +912,14 @@ MountConfigListView.prototype = _.extend({
|
|||
success: function(result) {
|
||||
var onCompletion = jQuery.Deferred();
|
||||
$.each(result, function(i, storageParams) {
|
||||
var storageConfig;
|
||||
var isUserProvidedAuth = storageParams.authMechanism === 'password::userprovided';
|
||||
storageParams.mountPoint = storageParams.mountPoint.substr(1); // trim leading slash
|
||||
var storageConfig = new self._storageConfigClass();
|
||||
if (isUserProvidedAuth) {
|
||||
storageConfig = new UserGlobalStorageConfig();
|
||||
} else {
|
||||
storageConfig = new self._storageConfigClass();
|
||||
}
|
||||
_.extend(storageConfig, storageParams);
|
||||
var $tr = self.newStorage(storageConfig, onCompletion);
|
||||
|
||||
|
@ -878,12 +930,16 @@ MountConfigListView.prototype = _.extend({
|
|||
var $authentication = $tr.find('.authentication');
|
||||
$authentication.text($authentication.find('select option:selected').text());
|
||||
|
||||
// userglobal storages do not expose configuration data
|
||||
$tr.find('.configuration').text(t('files_external', 'Admin defined'));
|
||||
|
||||
// disable any other inputs
|
||||
$tr.find('.mountOptionsToggle, .remove').empty();
|
||||
$tr.find('input, select, button').attr('disabled', 'disabled');
|
||||
$tr.find('input:not(.user_provided), select:not(.user_provided)').attr('disabled', 'disabled');
|
||||
|
||||
if (isUserProvidedAuth) {
|
||||
$tr.find('.configuration').find(':not(.user_provided)').remove();
|
||||
} else {
|
||||
// userglobal storages do not expose configuration data
|
||||
$tr.find('.configuration').text(t('files_external', 'Admin defined'));
|
||||
}
|
||||
});
|
||||
onCompletion.resolve();
|
||||
}
|
||||
|
@ -918,22 +974,40 @@ MountConfigListView.prototype = _.extend({
|
|||
* @return {jQuery} newly created input
|
||||
*/
|
||||
writeParameterInput: function($td, parameter, placeholder, classes) {
|
||||
var hasFlag = function(flag) {
|
||||
return placeholder.indexOf(flag) !== -1;
|
||||
};
|
||||
classes = $.isArray(classes) ? classes : [];
|
||||
classes.push('added');
|
||||
if (placeholder.indexOf('&') === 0) {
|
||||
classes.push('optional');
|
||||
placeholder = placeholder.substring(1);
|
||||
}
|
||||
|
||||
if (hasFlag('@')) {
|
||||
if (this._isPersonal) {
|
||||
classes.push('user_provided');
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
var trimmedPlaceholder = placeholder;
|
||||
var flags = ['@', '*', '!', '#', '&'];
|
||||
while(flags.indexOf(trimmedPlaceholder[0]) !== -1) {
|
||||
trimmedPlaceholder = trimmedPlaceholder.substr(1);
|
||||
}
|
||||
if (hasFlag('*')) {
|
||||
newElement = $('<input type="password" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" placeholder="'+ trimmedPlaceholder+'" />');
|
||||
} else if (hasFlag('!')) {
|
||||
var checkboxId = _.uniqueId('checkbox_');
|
||||
newElement = $('<input type="checkbox" id="'+checkboxId+'" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" /><label for="'+checkboxId+'">'+placeholder.substring(1)+'</label>');
|
||||
} else if (placeholder.indexOf('#') === 0) {
|
||||
newElement = $('<input type="checkbox" id="'+checkboxId+'" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" /><label for="'+checkboxId+'">'+ trimmedPlaceholder+'</label>');
|
||||
} else if (hasFlag('#')) {
|
||||
newElement = $('<input type="hidden" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" />');
|
||||
} else {
|
||||
newElement = $('<input type="text" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" placeholder="'+placeholder+'" />');
|
||||
newElement = $('<input type="text" class="'+classes.join(' ')+'" data-parameter="'+parameter+'" placeholder="'+ trimmedPlaceholder+'" />');
|
||||
}
|
||||
highlightInput(newElement);
|
||||
$td.append(newElement);
|
||||
|
@ -952,7 +1026,12 @@ MountConfigListView.prototype = _.extend({
|
|||
// new entry
|
||||
storageId = null;
|
||||
}
|
||||
var storage = new this._storageConfigClass(storageId);
|
||||
|
||||
var storage = $tr.data('storageConfig');
|
||||
if (!storage) {
|
||||
storage = new this._storageConfigClass(storageId);
|
||||
}
|
||||
storage.errors = null;
|
||||
storage.mountPoint = $tr.find('.mountPoint input').val();
|
||||
storage.backend = $tr.find('.backend').data('identifier');
|
||||
storage.authMechanism = $tr.find('.selectAuthMechanism').val();
|
||||
|
@ -966,7 +1045,7 @@ MountConfigListView.prototype = _.extend({
|
|||
if ($input.attr('type') === 'button') {
|
||||
return;
|
||||
}
|
||||
if (!isInputValid($input)) {
|
||||
if (!isInputValid($input) && !$input.hasClass('optional')) {
|
||||
missingOptions.push(parameter);
|
||||
return;
|
||||
}
|
||||
|
@ -994,7 +1073,7 @@ MountConfigListView.prototype = _.extend({
|
|||
var users = [];
|
||||
var multiselect = getSelection($tr);
|
||||
$.each(multiselect, function(index, value) {
|
||||
var pos = value.indexOf('(group)');
|
||||
var pos = (value.indexOf)?value.indexOf('(group)'): -1;
|
||||
if (pos !== -1) {
|
||||
groups.push(value.substr(0, pos));
|
||||
} else {
|
||||
|
@ -1057,7 +1136,9 @@ MountConfigListView.prototype = _.extend({
|
|||
saveStorageConfig:function($tr, callback, concurrentTimer) {
|
||||
var self = this;
|
||||
var storage = this.getStorageConfig($tr);
|
||||
if (!storage.validate()) {
|
||||
console.log(storage);
|
||||
if (!storage || !storage.validate()) {
|
||||
console.log('invalid');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
namespace OCA\Files_External\Lib\Auth\Password;
|
||||
|
||||
use OCA\Files_External\Lib\DefinitionParameter;
|
||||
use OCP\IL10N;
|
||||
use OCP\IUser;
|
||||
use OCA\Files_External\Lib\Auth\AuthMechanism;
|
||||
|
@ -46,7 +47,13 @@ class UserProvided extends AuthMechanism {
|
|||
->setIdentifier('password::userprovided')
|
||||
->setScheme(self::SCHEME_PASSWORD)
|
||||
->setText($l->t('User provided'))
|
||||
->addParameters([]);
|
||||
->addParameters([
|
||||
(new DefinitionParameter('user', $l->t('Username')))
|
||||
->setFlag(DefinitionParameter::FLAG_USER_PROVIDED),
|
||||
(new DefinitionParameter('password', $l->t('Password')))
|
||||
->setType(DefinitionParameter::VALUE_PASSWORD)
|
||||
->setFlag(DefinitionParameter::FLAG_USER_PROVIDED),
|
||||
]);
|
||||
}
|
||||
|
||||
private function getCredentialsIdentifier($storageId) {
|
||||
|
|
|
@ -35,6 +35,7 @@ class DefinitionParameter implements \JsonSerializable {
|
|||
/** Flag constants */
|
||||
const FLAG_NONE = 0;
|
||||
const FLAG_OPTIONAL = 1;
|
||||
const FLAG_USER_PROVIDED = 2;
|
||||
|
||||
/** @var string name of parameter */
|
||||
private $name;
|
||||
|
@ -121,7 +122,7 @@ class DefinitionParameter implements \JsonSerializable {
|
|||
* @return bool
|
||||
*/
|
||||
public function isFlagSet($flag) {
|
||||
return (bool) $this->flags & $flag;
|
||||
return (bool)($this->flags & $flag);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -143,10 +144,11 @@ class DefinitionParameter implements \JsonSerializable {
|
|||
break;
|
||||
}
|
||||
|
||||
switch ($this->getFlags()) {
|
||||
case self::FLAG_OPTIONAL:
|
||||
$prefix = '&' . $prefix;
|
||||
break;
|
||||
if ($this->isFlagSet(self::FLAG_OPTIONAL)) {
|
||||
$prefix = '&' . $prefix;
|
||||
}
|
||||
if ($this->isFlagSet(self::FLAG_USER_PROVIDED)) {
|
||||
$prefix = '@' . $prefix;
|
||||
}
|
||||
|
||||
return $prefix . $this->getText();
|
||||
|
@ -160,28 +162,28 @@ class DefinitionParameter implements \JsonSerializable {
|
|||
* @return bool success
|
||||
*/
|
||||
public function validateValue(&$value) {
|
||||
$optional = $this->getFlags() & self::FLAG_OPTIONAL;
|
||||
$optional = $this->isFlagSet(self::FLAG_OPTIONAL) || $this->isFlagSet(self::FLAG_USER_PROVIDED);
|
||||
|
||||
switch ($this->getType()) {
|
||||
case self::VALUE_BOOLEAN:
|
||||
if (!is_bool($value)) {
|
||||
switch ($value) {
|
||||
case 'true':
|
||||
$value = true;
|
||||
break;
|
||||
case 'false':
|
||||
$value = false;
|
||||
break;
|
||||
default:
|
||||
case self::VALUE_BOOLEAN:
|
||||
if (!is_bool($value)) {
|
||||
switch ($value) {
|
||||
case 'true':
|
||||
$value = true;
|
||||
break;
|
||||
case 'false':
|
||||
$value = false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!$value && !$optional) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!$value && !$optional) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue