From f505883e452f3c1e2653096f57e3494e0546fc46 Mon Sep 17 00:00:00 2001 From: Robin McCorkell Date: Wed, 12 Aug 2015 22:01:21 +0100 Subject: [PATCH 1/4] Add on-backend and on-auth-mechanism events to JS --- apps/files_external/js/settings.js | 34 ++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index d3e20e384457..b542fe63d642 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -550,7 +550,7 @@ var MountConfigListView = function($el, options) { /** * @memberOf OCA.External.Settings */ -MountConfigListView.prototype = { +MountConfigListView.prototype = _.extend({ /** * jQuery element containing the config list @@ -644,11 +644,31 @@ MountConfigListView.prototype = { addSelect2(this.$el.find('tr:not(#addMountPoint) .applicableUsers'), this._userListLimit); - this.$el.find('tr:not(#addMountPoint)').each(function(i, tr) { + this._initEvents(); + + this.$el.find('tbody tr:not(#addMountPoint)').each(function(i, tr) { self.recheckStorageConfig($(tr)); }); + }, - this._initEvents(); + /** + * Custom JS event handlers + * Trigger callback for all existing configurations + */ + whenSelectBackend: function(callback) { + this.$el.find('tbody tr:not(#addMountPoint)').each(function(i, tr) { + var backend = $(tr).find('.backend').data('class'); + callback($(tr), backend); + }); + this.on('selectBackend', callback); + }, + whenSelectAuthMechanism: function(callback) { + var self = this; + this.$el.find('tbody tr:not(#addMountPoint)').each(function(i, tr) { + var authMechanism = $(tr).find('.selectAuthMechanism').val(); + callback($(tr), authMechanism, self._allAuthMechanisms[authMechanism]['scheme']); + }); + this.on('selectAuthMechanism', callback); }, /** @@ -728,6 +748,8 @@ MountConfigListView.prototype = { var $td = $tr.find('td.configuration'); $.each(backendConfiguration['configuration'], _.partial(this.writeParameterInput, $td)); + this.trigger('selectBackend', $tr, backend); + selectAuthMechanism.trigger('change'); // generate configuration parameters for auth mechanism var priorityEl = $(''); @@ -758,6 +780,10 @@ MountConfigListView.prototype = { this.writeParameterInput, $td, _, _, ['auth-param'] )); + this.trigger('selectAuthMechanism', + $tr, authMechanism, authMechanismConfiguration['scheme'] + ); + if ($tr.data('constructing') !== true) { // row is ready, trigger recheck this.saveStorageConfig($tr); @@ -1045,7 +1071,7 @@ MountConfigListView.prototype = { self.saveStorageConfig($tr); }); } -}; +}, OC.Backbone.Events); $(document).ready(function() { var enabled = $('#files_external').attr('data-encryption-enabled'); From ced04f9ad2a55439d74681ce1a582a5c6ed2d5ab Mon Sep 17 00:00:00 2001 From: Robin McCorkell Date: Wed, 12 Aug 2015 21:58:22 +0100 Subject: [PATCH 2/4] Migrate AmazonS3 external storage to new API --- apps/files_external/appinfo/app.php | 27 --------- apps/files_external/appinfo/application.php | 4 ++ .../lib/auth/amazons3/accesskey.php | 47 +++++++++++++++ apps/files_external/lib/backend/amazons3.php | 58 +++++++++++++++++++ 4 files changed, 109 insertions(+), 27 deletions(-) create mode 100644 apps/files_external/lib/auth/amazons3/accesskey.php create mode 100644 apps/files_external/lib/backend/amazons3.php diff --git a/apps/files_external/appinfo/app.php b/apps/files_external/appinfo/app.php index 3d8e610db4d0..241e29be402c 100644 --- a/apps/files_external/appinfo/app.php +++ b/apps/files_external/appinfo/app.php @@ -70,33 +70,6 @@ OCP\Util::connectHook('OC_Filesystem', 'post_initMountPoints', '\OC_Mount_Config', 'initMountPointsHook'); OCP\Util::connectHook('OC_User', 'post_login', 'OC\Files\Storage\SMB_OC', 'login'); -OC_Mount_Config::registerBackend('\OC\Files\Storage\AmazonS3', [ - 'backend' => (string)$l->t('Amazon S3'), - 'priority' => 100, - 'configuration' => [ - 'key' => (string)$l->t('Key'), - 'secret' => '*'.$l->t('Secret'), - 'bucket' => (string)$l->t('Bucket'), - ], - 'has_dependencies' => true, -]); - -OC_Mount_Config::registerBackend('\OC\Files\Storage\AmazonS3', [ - 'backend' => (string)$l->t('Amazon S3 and compliant'), - 'priority' => 100, - 'configuration' => [ - 'key' => (string)$l->t('Access Key'), - 'secret' => '*'.$l->t('Secret Key'), - 'bucket' => (string)$l->t('Bucket'), - 'hostname' => '&'.$l->t('Hostname'), - 'port' => '&'.$l->t('Port'), - 'region' => '&'.$l->t('Region'), - 'use_ssl' => '!'.$l->t('Enable SSL'), - 'use_path_style' => '!'.$l->t('Enable Path Style') - ], - 'has_dependencies' => true, -]); - OC_Mount_Config::registerBackend('\OC\Files\Storage\Dropbox', [ 'backend' => 'Dropbox', 'priority' => 100, diff --git a/apps/files_external/appinfo/application.php b/apps/files_external/appinfo/application.php index 4520a8737beb..5f83e1bf91c0 100644 --- a/apps/files_external/appinfo/application.php +++ b/apps/files_external/appinfo/application.php @@ -65,6 +65,7 @@ protected function loadBackends() { $container->query('OCA\Files_External\Lib\Backend\DAV'), $container->query('OCA\Files_External\Lib\Backend\OwnCloud'), $container->query('OCA\Files_External\Lib\Backend\SFTP'), + $container->query('OCA\Files_External\Lib\Backend\AmazonS3'), ]); if (!\OC_Util::runningOnWindows()) { @@ -91,6 +92,9 @@ protected function loadAuthMechanisms() { // AuthMechanism::SCHEME_PASSWORD mechanisms $container->query('OCA\Files_External\Lib\Auth\Password\Password'), $container->query('OCA\Files_External\Lib\Auth\Password\SessionCredentials'), + + // Specialized mechanisms + $container->query('OCA\Files_External\Lib\Auth\AmazonS3\AccessKey'), ]); } diff --git a/apps/files_external/lib/auth/amazons3/accesskey.php b/apps/files_external/lib/auth/amazons3/accesskey.php new file mode 100644 index 000000000000..9e3aab374b90 --- /dev/null +++ b/apps/files_external/lib/auth/amazons3/accesskey.php @@ -0,0 +1,47 @@ + + * + * @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 + * + */ + +namespace OCA\Files_External\Lib\Auth\AmazonS3; + +use \OCP\IL10N; +use \OCA\Files_External\Lib\DefinitionParameter; +use \OCA\Files_External\Lib\Auth\AuthMechanism; + +/** + * Amazon S3 access key authentication + */ +class AccessKey extends AuthMechanism { + + const SCHEME_AMAZONS3_ACCESSKEY = 'amazons3_accesskey'; + + public function __construct(IL10N $l) { + $this + ->setIdentifier('amazons3::accesskey') + ->setScheme(self::SCHEME_AMAZONS3_ACCESSKEY) + ->setText($l->t('Access key')) + ->addParameters([ + (new DefinitionParameter('key', $l->t('Access key'))), + (new DefinitionParameter('secret', $l->t('Secret key'))) + ->setType(DefinitionParameter::VALUE_PASSWORD), + ]); + } + +} diff --git a/apps/files_external/lib/backend/amazons3.php b/apps/files_external/lib/backend/amazons3.php new file mode 100644 index 000000000000..880d47621f3b --- /dev/null +++ b/apps/files_external/lib/backend/amazons3.php @@ -0,0 +1,58 @@ + + * + * @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 + * + */ + +namespace OCA\Files_External\Lib\Backend; + +use \OCP\IL10N; +use \OCA\Files_External\Lib\Backend\Backend; +use \OCA\Files_External\Lib\DefinitionParameter; +use \OCA\Files_External\Lib\Auth\AuthMechanism; +use \OCA\Files_External\Service\BackendService; +use \OCA\Files_External\Lib\Auth\AmazonS3\AccessKey; + +class AmazonS3 extends Backend { + + public function __construct(IL10N $l, AccessKey $legacyAuth) { + $this + ->setIdentifier('amazons3') + ->addIdentifierAlias('\OC\Files\Storage\AmazonS3') // legacy compat + ->setStorageClass('\OC\Files\Storage\AmazonS3') + ->setText($l->t('Amazon S3')) + ->addParameters([ + (new DefinitionParameter('bucket', $l->t('Bucket'))), + (new DefinitionParameter('hostname', $l->t('Hostname'))) + ->setFlag(DefinitionParameter::FLAG_OPTIONAL), + (new DefinitionParameter('port', $l->t('Port'))) + ->setFlag(DefinitionParameter::FLAG_OPTIONAL), + (new DefinitionParameter('region', $l->t('Region'))) + ->setFlag(DefinitionParameter::FLAG_OPTIONAL), + (new DefinitionParameter('use_ssl', $l->t('Enable SSL'))) + ->setType(DefinitionParameter::VALUE_BOOLEAN), + (new DefinitionParameter('use_path_style', $l->t('Enable Path Style'))) + ->setType(DefinitionParameter::VALUE_BOOLEAN), + ]) + ->setDependencyCheck('\OC\Files\Storage\AmazonS3::checkDependencies') + ->addAuthScheme(AccessKey::SCHEME_AMAZONS3_ACCESSKEY) + ->setLegacyAuthMechanism($legacyAuth) + ; + } + +} From a50ef618761ae3588d00e55c39451cba75672e7f Mon Sep 17 00:00:00 2001 From: Robin McCorkell Date: Wed, 12 Aug 2015 22:03:41 +0100 Subject: [PATCH 3/4] Migrate Dropbox external storage to new API --- .../ajax/{dropbox.php => oauth1.php} | 7 +- apps/files_external/appinfo/app.php | 14 --- apps/files_external/appinfo/application.php | 4 + apps/files_external/appinfo/routes.php | 4 +- apps/files_external/js/dropbox.js | 111 ------------------ apps/files_external/js/oauth1.js | 78 ++++++++++++ .../files_external/lib/auth/oauth1/oauth1.php | 53 +++++++++ apps/files_external/lib/backend/dropbox.php | 48 ++++++++ 8 files changed, 189 insertions(+), 130 deletions(-) rename apps/files_external/ajax/{dropbox.php => oauth1.php} (89%) delete mode 100644 apps/files_external/js/dropbox.js create mode 100644 apps/files_external/js/oauth1.js create mode 100644 apps/files_external/lib/auth/oauth1/oauth1.php create mode 100644 apps/files_external/lib/backend/dropbox.php diff --git a/apps/files_external/ajax/dropbox.php b/apps/files_external/ajax/oauth1.php similarity index 89% rename from apps/files_external/ajax/dropbox.php rename to apps/files_external/ajax/oauth1.php index 55dc417b73a3..ca339aeec584 100644 --- a/apps/files_external/ajax/dropbox.php +++ b/apps/files_external/ajax/oauth1.php @@ -30,6 +30,7 @@ OCP\JSON::callCheck(); $l = \OC::$server->getL10N('files_external'); +// FIXME: currently hard-coded to Dropbox OAuth if (isset($_POST['app_key']) && isset($_POST['app_secret'])) { $oauth = new Dropbox_OAuth_Curl((string)$_POST['app_key'], (string)$_POST['app_secret']); if (isset($_POST['step'])) { @@ -47,7 +48,7 @@ 'request_token_secret' => $token['token_secret']))); } catch (Exception $exception) { OCP\JSON::error(array('data' => array('message' => - $l->t('Fetching request tokens failed. Verify that your Dropbox app key and secret are correct.')) + $l->t('Fetching request tokens failed. Verify that your app key and secret are correct.')) )); } break; @@ -60,7 +61,7 @@ 'access_token_secret' => $token['token_secret'])); } catch (Exception $exception) { OCP\JSON::error(array('data' => array('message' => - $l->t('Fetching access tokens failed. Verify that your Dropbox app key and secret are correct.')) + $l->t('Fetching access tokens failed. Verify that your app key and secret are correct.')) )); } } @@ -68,5 +69,5 @@ } } } else { - OCP\JSON::error(array('data' => array('message' => $l->t('Please provide a valid Dropbox app key and secret.')))); + OCP\JSON::error(array('data' => array('message' => $l->t('Please provide a valid app key and secret.')))); } diff --git a/apps/files_external/appinfo/app.php b/apps/files_external/appinfo/app.php index 241e29be402c..14edfe3538bd 100644 --- a/apps/files_external/appinfo/app.php +++ b/apps/files_external/appinfo/app.php @@ -70,20 +70,6 @@ OCP\Util::connectHook('OC_Filesystem', 'post_initMountPoints', '\OC_Mount_Config', 'initMountPointsHook'); OCP\Util::connectHook('OC_User', 'post_login', 'OC\Files\Storage\SMB_OC', 'login'); -OC_Mount_Config::registerBackend('\OC\Files\Storage\Dropbox', [ - 'backend' => 'Dropbox', - 'priority' => 100, - 'configuration' => [ - 'configured' => '#configured', - 'app_key' => (string)$l->t('App key'), - 'app_secret' => '*'.$l->t('App secret'), - 'token' => '#token', - 'token_secret' => '#token_secret' - ], - 'custom' => 'dropbox', - 'has_dependencies' => true, -]); - OC_Mount_Config::registerBackend('\OC\Files\Storage\Google', [ 'backend' => 'Google Drive', 'priority' => 100, diff --git a/apps/files_external/appinfo/application.php b/apps/files_external/appinfo/application.php index 5f83e1bf91c0..4a9a7a6b8278 100644 --- a/apps/files_external/appinfo/application.php +++ b/apps/files_external/appinfo/application.php @@ -66,6 +66,7 @@ protected function loadBackends() { $container->query('OCA\Files_External\Lib\Backend\OwnCloud'), $container->query('OCA\Files_External\Lib\Backend\SFTP'), $container->query('OCA\Files_External\Lib\Backend\AmazonS3'), + $container->query('OCA\Files_External\Lib\Backend\Dropbox'), ]); if (!\OC_Util::runningOnWindows()) { @@ -93,6 +94,9 @@ protected function loadAuthMechanisms() { $container->query('OCA\Files_External\Lib\Auth\Password\Password'), $container->query('OCA\Files_External\Lib\Auth\Password\SessionCredentials'), + // AuthMechanism::SCHEME_OAUTH1 mechanisms + $container->query('OCA\Files_External\Lib\Auth\OAuth1\OAuth1'), + // Specialized mechanisms $container->query('OCA\Files_External\Lib\Auth\AmazonS3\AccessKey'), ]); diff --git a/apps/files_external/appinfo/routes.php b/apps/files_external/appinfo/routes.php index 4462ad1f274c..ccc50cbd0f96 100644 --- a/apps/files_external/appinfo/routes.php +++ b/apps/files_external/appinfo/routes.php @@ -46,8 +46,8 @@ ) ); -$this->create('files_external_dropbox', 'ajax/dropbox.php') - ->actionInclude('files_external/ajax/dropbox.php'); +$this->create('files_external_oauth1', 'ajax/oauth1.php') + ->actionInclude('files_external/ajax/oauth1.php'); $this->create('files_external_google', 'ajax/google.php') ->actionInclude('files_external/ajax/google.php'); diff --git a/apps/files_external/js/dropbox.js b/apps/files_external/js/dropbox.js deleted file mode 100644 index 53b5d5d666fb..000000000000 --- a/apps/files_external/js/dropbox.js +++ /dev/null @@ -1,111 +0,0 @@ -$(document).ready(function() { - - $('#externalStorage tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Dropbox').each(function() { - var configured = $(this).find('[data-parameter="configured"]'); - if ($(configured).val() == 'true') { - $(this).find('.configuration input').attr('disabled', 'disabled'); - $(this).find('.configuration').append(''+t('files_external', 'Access granted')+''); - } else { - var app_key = $(this).find('.configuration [data-parameter="app_key"]').val(); - var app_secret = $(this).find('.configuration [data-parameter="app_secret"]').val(); - var config = $(this).find('.configuration'); - if (app_key != '' && app_secret != '') { - var pos = window.location.search.indexOf('oauth_token') + 12; - var token = $(this).find('.configuration [data-parameter="token"]'); - if (pos != -1 && window.location.search.substr(pos, $(token).val().length) == $(token).val()) { - var token_secret = $(this).find('.configuration [data-parameter="token_secret"]'); - var tr = $(this); - var statusSpan = $(tr).find('.status span'); - statusSpan.removeClass(); - statusSpan.addClass('waiting'); - $.post(OC.filePath('files_external', 'ajax', 'dropbox.php'), { step: 2, app_key: app_key, app_secret: app_secret, request_token: $(token).val(), request_token_secret: $(token_secret).val() }, function(result) { - if (result && result.status == 'success') { - $(token).val(result.access_token); - $(token_secret).val(result.access_token_secret); - $(configured).val('true'); - OCA.External.Settings.mountConfig.saveStorageConfig(tr, function(status) { - if (status) { - $(tr).find('.configuration input').attr('disabled', 'disabled'); - $(tr).find('.configuration').append(''+t('files_external', 'Access granted')+''); - } - }); - } else { - OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Dropbox storage')); - } - }); - } - } else { - onDropboxInputsChange($(this)); - } - } - }); - - $('#externalStorage').on('paste', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Dropbox td', function() { - var tr = $(this).parent(); - setTimeout(function() { - onDropboxInputsChange(tr); - }, 20); - }); - - $('#externalStorage').on('keyup', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Dropbox td', function() { - onDropboxInputsChange($(this).parent()); - }); - - $('#externalStorage').on('change', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Dropbox .chzn-select', function() { - onDropboxInputsChange($(this).parent().parent()); - }); - - function onDropboxInputsChange(tr) { - if ($(tr).find('[data-parameter="configured"]').val() != 'true') { - var config = $(tr).find('.configuration'); - if ($(tr).find('.mountPoint input').val() != '' - && $(config).find('[data-parameter="app_key"]').val() != '' - && $(config).find('[data-parameter="app_secret"]').val() != '' - && ($(tr).find('.chzn-select').length == 0 - || $(tr).find('.chzn-select').val() != null)) - { - if ($(tr).find('.dropbox').length == 0) { - $(config).append($(document.createElement('input')) - .addClass('button dropbox') - .attr('type', 'button') - .attr('value', t('files_external', 'Grant access'))); - } else { - $(tr).find('.dropbox').show(); - } - } else if ($(tr).find('.dropbox').length > 0) { - $(tr).find('.dropbox').hide(); - } - } - } - - $('#externalStorage').on('click', '.dropbox', function(event) { - event.preventDefault(); - var tr = $(this).parent().parent(); - var app_key = $(this).parent().find('[data-parameter="app_key"]').val(); - var app_secret = $(this).parent().find('[data-parameter="app_secret"]').val(); - if (app_key != '' && app_secret != '') { - var tr = $(this).parent().parent(); - var configured = $(this).parent().find('[data-parameter="configured"]'); - var token = $(this).parent().find('[data-parameter="token"]'); - var token_secret = $(this).parent().find('[data-parameter="token_secret"]'); - $.post(OC.filePath('files_external', 'ajax', 'dropbox.php'), { step: 1, app_key: app_key, app_secret: app_secret, callback: location.protocol + '//' + location.host + location.pathname }, function(result) { - if (result && result.status == 'success') { - $(configured).val('false'); - $(token).val(result.data.request_token); - $(token_secret).val(result.data.request_token_secret); - OCA.External.Settings.mountConfig.saveStorageConfig(tr, function() { - window.location = result.data.url; - }); - } else { - OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Dropbox storage')); - } - }); - } else { - OC.dialogs.alert( - t('files_external', 'Please provide a valid Dropbox app key and secret.'), - t('files_external', 'Error configuring Dropbox storage') - ); - } - }); - -}); diff --git a/apps/files_external/js/oauth1.js b/apps/files_external/js/oauth1.js new file mode 100644 index 000000000000..47aca36871fd --- /dev/null +++ b/apps/files_external/js/oauth1.js @@ -0,0 +1,78 @@ +$(document).ready(function() { + + OCA.External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme) { + if (authMechanism === 'oauth1::oauth1') { + var config = $tr.find('.configuration'); + config.append($(document.createElement('input')) + .addClass('button auth-param') + .attr('type', 'button') + .attr('value', t('files_external', 'Grant access')) + .attr('name', 'oauth1_grant') + ); + + var configured = $tr.find('[data-parameter="configured"]'); + if ($(configured).val() == 'true') { + $tr.find('.configuration input').attr('disabled', 'disabled'); + $tr.find('.configuration').append(''+t('files_external', 'Access granted')+''); + } else { + var app_key = $tr.find('.configuration [data-parameter="app_key"]').val(); + var app_secret = $tr.find('.configuration [data-parameter="app_secret"]').val(); + if (app_key != '' && app_secret != '') { + var pos = window.location.search.indexOf('oauth_token') + 12; + var token = $tr.find('.configuration [data-parameter="token"]'); + if (pos != -1 && window.location.search.substr(pos, $(token).val().length) == $(token).val()) { + var token_secret = $tr.find('.configuration [data-parameter="token_secret"]'); + var statusSpan = $tr.find('.status span'); + statusSpan.removeClass(); + statusSpan.addClass('waiting'); + $.post(OC.filePath('files_external', 'ajax', 'oauth1.php'), { step: 2, app_key: app_key, app_secret: app_secret, request_token: $(token).val(), request_token_secret: $(token_secret).val() }, function(result) { + if (result && result.status == 'success') { + $(token).val(result.access_token); + $(token_secret).val(result.access_token_secret); + $(configured).val('true'); + OCA.External.Settings.mountConfig.saveStorageConfig($tr, function(status) { + if (status) { + $tr.find('.configuration input').attr('disabled', 'disabled'); + $tr.find('.configuration').append(''+t('files_external', 'Access granted')+''); + } + }); + } else { + OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring OAuth1')); + } + }); + } + } + } + } + }); + + $('#externalStorage').on('click', '[name="oauth1_grant"]', function(event) { + event.preventDefault(); + var tr = $(this).parent().parent(); + var app_key = $(this).parent().find('[data-parameter="app_key"]').val(); + var app_secret = $(this).parent().find('[data-parameter="app_secret"]').val(); + if (app_key != '' && app_secret != '') { + var configured = $(this).parent().find('[data-parameter="configured"]'); + var token = $(this).parent().find('[data-parameter="token"]'); + var token_secret = $(this).parent().find('[data-parameter="token_secret"]'); + $.post(OC.filePath('files_external', 'ajax', 'oauth1.php'), { step: 1, app_key: app_key, app_secret: app_secret, callback: location.protocol + '//' + location.host + location.pathname }, function(result) { + if (result && result.status == 'success') { + $(configured).val('false'); + $(token).val(result.data.request_token); + $(token_secret).val(result.data.request_token_secret); + OCA.External.Settings.mountConfig.saveStorageConfig(tr, function() { + window.location = result.data.url; + }); + } else { + OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring OAuth1')); + } + }); + } else { + OC.dialogs.alert( + t('files_external', 'Please provide a valid app key and secret.'), + t('files_external', 'Error configuring OAuth1') + ); + } + }); + +}); diff --git a/apps/files_external/lib/auth/oauth1/oauth1.php b/apps/files_external/lib/auth/oauth1/oauth1.php new file mode 100644 index 000000000000..3fb1b16aa6d2 --- /dev/null +++ b/apps/files_external/lib/auth/oauth1/oauth1.php @@ -0,0 +1,53 @@ + + * + * @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 + * + */ + +namespace OCA\Files_External\Lib\Auth\OAuth1; + +use \OCP\IL10N; +use \OCA\Files_External\Lib\DefinitionParameter; +use \OCA\Files_External\Lib\Auth\AuthMechanism; + +/** + * OAuth1 authentication + */ +class OAuth1 extends AuthMechanism { + + public function __construct(IL10N $l) { + $this + ->setIdentifier('oauth1::oauth1') + ->setScheme(self::SCHEME_OAUTH1) + ->setText($l->t('OAuth1')) + ->addParameters([ + (new DefinitionParameter('configured', 'configured')) + ->setType(DefinitionParameter::VALUE_HIDDEN), + (new DefinitionParameter('app_key', $l->t('App key'))), + (new DefinitionParameter('app_secret', $l->t('App secret'))) + ->setType(DefinitionParameter::VALUE_PASSWORD), + (new DefinitionParameter('token', 'token')) + ->setType(DefinitionParameter::VALUE_HIDDEN), + (new DefinitionParameter('token_secret', 'token_secret')) + ->setType(DefinitionParameter::VALUE_HIDDEN), + ]) + ->setCustomJs('oauth1') + ; + } + +} diff --git a/apps/files_external/lib/backend/dropbox.php b/apps/files_external/lib/backend/dropbox.php new file mode 100644 index 000000000000..bfd2e4cddc49 --- /dev/null +++ b/apps/files_external/lib/backend/dropbox.php @@ -0,0 +1,48 @@ + + * + * @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 + * + */ + +namespace OCA\Files_External\Lib\Backend; + +use \OCP\IL10N; +use \OCA\Files_External\Lib\Backend\Backend; +use \OCA\Files_External\Lib\DefinitionParameter; +use \OCA\Files_External\Lib\Auth\AuthMechanism; +use \OCA\Files_External\Service\BackendService; +use \OCA\Files_External\Lib\Auth\OAuth1\OAuth1; + +class Dropbox extends Backend { + + public function __construct(IL10N $l, OAuth1 $legacyAuth) { + $this + ->setIdentifier('dropbox') + ->addIdentifierAlias('\OC\Files\Storage\Dropbox') // legacy compat + ->setStorageClass('\OC\Files\Storage\Dropbox') + ->setText($l->t('Dropbox')) + ->addParameters([ + // all parameters handled in OAuth1 mechanism + ]) + ->setDependencyCheck('\OC\Files\Storage\Dropbox::checkDependencies') + ->addAuthScheme(AuthMechanism::SCHEME_OAUTH1) + ->setLegacyAuthMechanism($legacyAuth) + ; + } + +} From 88a78237b01bae66786f9c32f30b936240ea6f58 Mon Sep 17 00:00:00 2001 From: Robin McCorkell Date: Wed, 12 Aug 2015 22:09:20 +0100 Subject: [PATCH 4/4] Migrate Google external storage to new API --- .../ajax/{google.php => oauth2.php} | 1 + apps/files_external/appinfo/app.php | 14 -- apps/files_external/appinfo/application.php | 4 + apps/files_external/appinfo/routes.php | 4 +- apps/files_external/js/google.js | 131 ------------------ apps/files_external/js/oauth2.js | 95 +++++++++++++ .../files_external/lib/auth/oauth2/oauth2.php | 51 +++++++ apps/files_external/lib/backend/google.php | 48 +++++++ 8 files changed, 201 insertions(+), 147 deletions(-) rename apps/files_external/ajax/{google.php => oauth2.php} (98%) delete mode 100644 apps/files_external/js/google.js create mode 100644 apps/files_external/js/oauth2.js create mode 100644 apps/files_external/lib/auth/oauth2/oauth2.php create mode 100644 apps/files_external/lib/backend/google.php diff --git a/apps/files_external/ajax/google.php b/apps/files_external/ajax/oauth2.php similarity index 98% rename from apps/files_external/ajax/google.php rename to apps/files_external/ajax/oauth2.php index acaf1b0b27f2..0a202e3ddcb2 100644 --- a/apps/files_external/ajax/google.php +++ b/apps/files_external/ajax/oauth2.php @@ -33,6 +33,7 @@ OCP\JSON::callCheck(); $l = \OC::$server->getL10N('files_external'); +// FIXME: currently hard-coded to Google Drive if (isset($_POST['client_id']) && isset($_POST['client_secret']) && isset($_POST['redirect'])) { $client = new Google_Client(); $client->setClientId((string)$_POST['client_id']); diff --git a/apps/files_external/appinfo/app.php b/apps/files_external/appinfo/app.php index 14edfe3538bd..9db4b0a63305 100644 --- a/apps/files_external/appinfo/app.php +++ b/apps/files_external/appinfo/app.php @@ -70,20 +70,6 @@ OCP\Util::connectHook('OC_Filesystem', 'post_initMountPoints', '\OC_Mount_Config', 'initMountPointsHook'); OCP\Util::connectHook('OC_User', 'post_login', 'OC\Files\Storage\SMB_OC', 'login'); -OC_Mount_Config::registerBackend('\OC\Files\Storage\Google', [ - 'backend' => 'Google Drive', - 'priority' => 100, - 'configuration' => [ - 'configured' => '#configured', - 'client_id' => (string)$l->t('Client ID'), - 'client_secret' => '*'.$l->t('Client secret'), - 'token' => '#token', - ], - 'custom' => 'google', - 'has_dependencies' => true, -]); - - OC_Mount_Config::registerBackend('\OC\Files\Storage\Swift', [ 'backend' => (string)$l->t('OpenStack Object Storage'), 'priority' => 100, diff --git a/apps/files_external/appinfo/application.php b/apps/files_external/appinfo/application.php index 4a9a7a6b8278..1e43c7374084 100644 --- a/apps/files_external/appinfo/application.php +++ b/apps/files_external/appinfo/application.php @@ -67,6 +67,7 @@ protected function loadBackends() { $container->query('OCA\Files_External\Lib\Backend\SFTP'), $container->query('OCA\Files_External\Lib\Backend\AmazonS3'), $container->query('OCA\Files_External\Lib\Backend\Dropbox'), + $container->query('OCA\Files_External\Lib\Backend\Google'), ]); if (!\OC_Util::runningOnWindows()) { @@ -97,6 +98,9 @@ protected function loadAuthMechanisms() { // AuthMechanism::SCHEME_OAUTH1 mechanisms $container->query('OCA\Files_External\Lib\Auth\OAuth1\OAuth1'), + // AuthMechanism::SCHEME_OAUTH2 mechanisms + $container->query('OCA\Files_External\Lib\Auth\OAuth2\OAuth2'), + // Specialized mechanisms $container->query('OCA\Files_External\Lib\Auth\AmazonS3\AccessKey'), ]); diff --git a/apps/files_external/appinfo/routes.php b/apps/files_external/appinfo/routes.php index ccc50cbd0f96..5d7018c3476e 100644 --- a/apps/files_external/appinfo/routes.php +++ b/apps/files_external/appinfo/routes.php @@ -48,8 +48,8 @@ $this->create('files_external_oauth1', 'ajax/oauth1.php') ->actionInclude('files_external/ajax/oauth1.php'); -$this->create('files_external_google', 'ajax/google.php') - ->actionInclude('files_external/ajax/google.php'); +$this->create('files_external_oauth2', 'ajax/oauth2.php') + ->actionInclude('files_external/ajax/oauth2.php'); $this->create('files_external_list_applicable', '/applicable') diff --git a/apps/files_external/js/google.js b/apps/files_external/js/google.js deleted file mode 100644 index 648538f80287..000000000000 --- a/apps/files_external/js/google.js +++ /dev/null @@ -1,131 +0,0 @@ -$(document).ready(function() { - - $('#externalStorage tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google').each(function() { - var configured = $(this).find('[data-parameter="configured"]'); - if ($(configured).val() == 'true') { - $(this).find('.configuration input').attr('disabled', 'disabled'); - $(this).find('.configuration').append($('').attr('id', 'access') - .text(t('files_external', 'Access granted'))); - } else { - var client_id = $(this).find('.configuration [data-parameter="client_id"]').val(); - var client_secret = $(this).find('.configuration [data-parameter="client_secret"]') - .val(); - if (client_id != '' && client_secret != '') { - var params = {}; - window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) { - params[key] = value; - }); - if (params['code'] !== undefined) { - var tr = $(this); - var token = $(this).find('.configuration [data-parameter="token"]'); - var statusSpan = $(tr).find('.status span'); - statusSpan.removeClass(); - statusSpan.addClass('waiting'); - $.post(OC.filePath('files_external', 'ajax', 'google.php'), - { - step: 2, - client_id: client_id, - client_secret: client_secret, - redirect: location.protocol + '//' + location.host + location.pathname, - code: params['code'], - }, function(result) { - if (result && result.status == 'success') { - $(token).val(result.data.token); - $(configured).val('true'); - OCA.External.Settings.mountConfig.saveStorageConfig(tr, function(status) { - if (status) { - $(tr).find('.configuration input').attr('disabled', 'disabled'); - $(tr).find('.configuration').append($('') - .attr('id', 'access') - .text(t('files_external', 'Access granted'))); - } - }); - } else { - OC.dialogs.alert(result.data.message, - t('files_external', 'Error configuring Google Drive storage') - ); - } - } - ); - } - } else { - onGoogleInputsChange($(this)); - } - } - }); - - $('#externalStorage').on('paste', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google td', - function() { - var tr = $(this).parent(); - setTimeout(function() { - onGoogleInputsChange(tr); - }, 20); - } - ); - - $('#externalStorage').on('keyup', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google td', - function() { - onGoogleInputsChange($(this).parent()); - } - ); - - $('#externalStorage').on('change', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google .chzn-select' - , function() { - onGoogleInputsChange($(this).parent().parent()); - } - ); - - function onGoogleInputsChange(tr) { - if ($(tr).find('[data-parameter="configured"]').val() != 'true') { - var config = $(tr).find('.configuration'); - if ($(tr).find('.mountPoint input').val() != '' - && $(config).find('[data-parameter="client_id"]').val() != '' - && $(config).find('[data-parameter="client_secret"]').val() != '' - && ($(tr).find('.chzn-select').length == 0 - || $(tr).find('.chzn-select').val() != null)) - { - if ($(tr).find('.google').length == 0) { - $(config).append($(document.createElement('input')).addClass('button google') - .attr('type', 'button') - .attr('value', t('files_external', 'Grant access'))); - } else { - $(tr).find('.google').show(); - } - } else if ($(tr).find('.google').length > 0) { - $(tr).find('.google').hide(); - } - } - } - - $('#externalStorage').on('click', '.google', function(event) { - event.preventDefault(); - var tr = $(this).parent().parent(); - var configured = $(this).parent().find('[data-parameter="configured"]'); - var client_id = $(this).parent().find('[data-parameter="client_id"]').val(); - var client_secret = $(this).parent().find('[data-parameter="client_secret"]').val(); - if (client_id != '' && client_secret != '') { - var token = $(this).parent().find('[data-parameter="token"]'); - $.post(OC.filePath('files_external', 'ajax', 'google.php'), - { - step: 1, - client_id: client_id, - client_secret: client_secret, - redirect: location.protocol + '//' + location.host + location.pathname, - }, function(result) { - if (result && result.status == 'success') { - $(configured).val('false'); - $(token).val('false'); - OCA.External.Settings.mountConfig.saveStorageConfig(tr, function(status) { - window.location = result.data.url; - }); - } else { - OC.dialogs.alert(result.data.message, - t('files_external', 'Error configuring Google Drive storage') - ); - } - } - ); - } - }); - -}); diff --git a/apps/files_external/js/oauth2.js b/apps/files_external/js/oauth2.js new file mode 100644 index 000000000000..849414374201 --- /dev/null +++ b/apps/files_external/js/oauth2.js @@ -0,0 +1,95 @@ +$(document).ready(function() { + + OCA.External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme) { + if (authMechanism === 'oauth2::oauth2') { + var config = $tr.find('.configuration'); + config.append($(document.createElement('input')) + .addClass('button auth-param') + .attr('type', 'button') + .attr('value', t('files_external', 'Grant access')) + .attr('name', 'oauth2_grant') + ); + + var configured = $tr.find('[data-parameter="configured"]'); + if ($(configured).val() == 'true') { + $tr.find('.configuration input').attr('disabled', 'disabled'); + $tr.find('.configuration').append($('').attr('id', 'access') + .text(t('files_external', 'Access granted'))); + } else { + var client_id = $tr.find('.configuration [data-parameter="client_id"]').val(); + var client_secret = $tr.find('.configuration [data-parameter="client_secret"]') + .val(); + if (client_id != '' && client_secret != '') { + var params = {}; + window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) { + params[key] = value; + }); + if (params['code'] !== undefined) { + var token = $tr.find('.configuration [data-parameter="token"]'); + var statusSpan = $tr.find('.status span'); + statusSpan.removeClass(); + statusSpan.addClass('waiting'); + $.post(OC.filePath('files_external', 'ajax', 'oauth2.php'), + { + step: 2, + client_id: client_id, + client_secret: client_secret, + redirect: location.protocol + '//' + location.host + location.pathname, + code: params['code'], + }, function(result) { + if (result && result.status == 'success') { + $(token).val(result.data.token); + $(configured).val('true'); + OCA.External.Settings.mountConfig.saveStorageConfig($tr, function(status) { + if (status) { + $tr.find('.configuration input').attr('disabled', 'disabled'); + $tr.find('.configuration').append($('') + .attr('id', 'access') + .text(t('files_external', 'Access granted'))); + } + }); + } else { + OC.dialogs.alert(result.data.message, + t('files_external', 'Error configuring OAuth2') + ); + } + } + ); + } + } + } + } + }); + + $('#externalStorage').on('click', '[name="oauth2_grant"]', function(event) { + event.preventDefault(); + var tr = $(this).parent().parent(); + var configured = $(this).parent().find('[data-parameter="configured"]'); + var client_id = $(this).parent().find('[data-parameter="client_id"]').val(); + var client_secret = $(this).parent().find('[data-parameter="client_secret"]').val(); + if (client_id != '' && client_secret != '') { + var token = $(this).parent().find('[data-parameter="token"]'); + $.post(OC.filePath('files_external', 'ajax', 'oauth2.php'), + { + step: 1, + client_id: client_id, + client_secret: client_secret, + redirect: location.protocol + '//' + location.host + location.pathname, + }, function(result) { + if (result && result.status == 'success') { + $(configured).val('false'); + $(token).val('false'); + OCA.External.Settings.mountConfig.saveStorageConfig(tr, function(status) { + window.location = result.data.url; + }); + } else { + OC.dialogs.alert(result.data.message, + t('files_external', 'Error configuring OAuth2') + ); + } + } + ); + } + }); + +}); diff --git a/apps/files_external/lib/auth/oauth2/oauth2.php b/apps/files_external/lib/auth/oauth2/oauth2.php new file mode 100644 index 000000000000..73faa85a44e9 --- /dev/null +++ b/apps/files_external/lib/auth/oauth2/oauth2.php @@ -0,0 +1,51 @@ + + * + * @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 + * + */ + +namespace OCA\Files_External\Lib\Auth\OAuth2; + +use \OCP\IL10N; +use \OCA\Files_External\Lib\DefinitionParameter; +use \OCA\Files_External\Lib\Auth\AuthMechanism; + +/** + * OAuth2 authentication + */ +class OAuth2 extends AuthMechanism { + + public function __construct(IL10N $l) { + $this + ->setIdentifier('oauth2::oauth2') + ->setScheme(self::SCHEME_OAUTH2) + ->setText($l->t('OAuth2')) + ->addParameters([ + (new DefinitionParameter('configured', 'configured')) + ->setType(DefinitionParameter::VALUE_HIDDEN), + (new DefinitionParameter('client_id', $l->t('Client ID'))), + (new DefinitionParameter('client_secret', $l->t('Client secret'))) + ->setType(DefinitionParameter::VALUE_PASSWORD), + (new DefinitionParameter('token', 'token')) + ->setType(DefinitionParameter::VALUE_HIDDEN), + ]) + ->setCustomJs('oauth2') + ; + } + +} diff --git a/apps/files_external/lib/backend/google.php b/apps/files_external/lib/backend/google.php new file mode 100644 index 000000000000..b46b2f653a64 --- /dev/null +++ b/apps/files_external/lib/backend/google.php @@ -0,0 +1,48 @@ + + * + * @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 + * + */ + +namespace OCA\Files_External\Lib\Backend; + +use \OCP\IL10N; +use \OCA\Files_External\Lib\Backend\Backend; +use \OCA\Files_External\Lib\DefinitionParameter; +use \OCA\Files_External\Lib\Auth\AuthMechanism; +use \OCA\Files_External\Service\BackendService; +use \OCA\Files_External\Lib\Auth\OAuth2\OAuth2; + +class Google extends Backend { + + public function __construct(IL10N $l, OAuth2 $legacyAuth) { + $this + ->setIdentifier('googledrive') + ->addIdentifierAlias('\OC\Files\Storage\Google') // legacy compat + ->setStorageClass('\OC\Files\Storage\Google') + ->setText($l->t('Google Drive')) + ->addParameters([ + // all parameters handled in OAuth2 mechanism + ]) + ->setDependencyCheck('\OC\Files\Storage\Google::checkDependencies') + ->addAuthScheme(AuthMechanism::SCHEME_OAUTH2) + ->setLegacyAuthMechanism($legacyAuth) + ; + } + +}