Skip to content

Commit 3847d98

Browse files
committed
Add option to disallow creation of local storages
Introduce a new config option to prevent web UI admins to create or edit external storages of type "local". Signed-off-by: Vincent Petry <vincent@nextcloud.com>
1 parent 3a1ef2b commit 3847d98

File tree

8 files changed

+125
-12
lines changed

8 files changed

+125
-12
lines changed

apps/files_external/js/settings.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,7 @@ MountConfigListView.prototype = _.extend({
659659
}
660660

661661
this._encryptionEnabled = options.encryptionEnabled;
662+
this._canCreateLocal = options.canCreateLocal;
662663

663664
// read the backend config that was carefully crammed
664665
// into the data-configurations attribute of the select
@@ -793,6 +794,7 @@ MountConfigListView.prototype = _.extend({
793794
newStorage: function(storageConfig, onCompletion) {
794795
var mountPoint = storageConfig.mountPoint;
795796
var backend = this._allBackends[storageConfig.backend];
797+
var readOnly = false;
796798

797799
if (!backend) {
798800
backend = {
@@ -801,6 +803,11 @@ MountConfigListView.prototype = _.extend({
801803
};
802804
}
803805

806+
console.log(backend, this._canCreateLocal);
807+
if (backend.identifier === 'local' && !this._canCreateLocal) {
808+
readOnly = true;
809+
}
810+
804811
// FIXME: Replace with a proper Handlebar template
805812
var $tr = this.$el.find('tr#addMountPoint');
806813
this.$el.find('tbody').append($tr.clone());
@@ -825,10 +832,13 @@ MountConfigListView.prototype = _.extend({
825832
$tr.addClass(backend.identifier);
826833
$tr.find('.backend').data('identifier', backend.identifier);
827834

828-
if (backend.invalid) {
835+
if (backend.invalid || readOnly) {
829836
$tr.find('[name=mountPoint]').prop('disabled', true);
830837
$tr.find('.applicable,.mountOptionsToggle').empty();
831-
this.updateStatus($tr, false, 'Unknown backend: ' + backend.name);
838+
$tr.find('.save').empty();
839+
if (backend.invalid) {
840+
this.updateStatus($tr, false, 'Unknown backend: ' + backend.name);
841+
}
832842
return $tr;
833843
}
834844

@@ -970,6 +980,7 @@ MountConfigListView.prototype = _.extend({
970980
var storageConfig = new self._storageConfigClass();
971981
_.extend(storageConfig, storageParams);
972982
var $tr = self.newStorage(storageConfig, onCompletion);
983+
973984
self.recheckStorageConfig($tr);
974985
});
975986
onCompletion.resolve();
@@ -1313,9 +1324,11 @@ MountConfigListView.prototype = _.extend({
13131324

13141325
window.addEventListener('DOMContentLoaded', function() {
13151326
var enabled = $('#files_external').attr('data-encryption-enabled');
1327+
var canCreateLocal = $('#files_external').attr('data-can-create-local');
13161328
var encryptionEnabled = (enabled ==='true')? true: false;
13171329
var mountConfigListView = new MountConfigListView($('#externalStorage'), {
1318-
encryptionEnabled: encryptionEnabled
1330+
encryptionEnabled: encryptionEnabled,
1331+
canCreateLocal: (canCreateLocal === 'true') ? true: false,
13191332
});
13201333
mountConfigListView.loadStorages();
13211334

apps/files_external/lib/Controller/GlobalStoragesController.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use OCA\Files_External\Service\GlobalStoragesService;
3232
use OCP\AppFramework\Http;
3333
use OCP\AppFramework\Http\DataResponse;
34+
use OCP\IConfig;
3435
use OCP\IGroupManager;
3536
use OCP\IL10N;
3637
use OCP\ILogger;
@@ -51,6 +52,7 @@ class GlobalStoragesController extends StoragesController {
5152
* @param ILogger $logger
5253
* @param IUserSession $userSession
5354
* @param IGroupManager $groupManager
55+
* @param IConfig $config
5456
*/
5557
public function __construct(
5658
$AppName,
@@ -59,7 +61,8 @@ public function __construct(
5961
GlobalStoragesService $globalStoragesService,
6062
ILogger $logger,
6163
IUserSession $userSession,
62-
IGroupManager $groupManager
64+
IGroupManager $groupManager,
65+
IConfig $config
6366
) {
6467
parent::__construct(
6568
$AppName,
@@ -68,7 +71,8 @@ public function __construct(
6871
$globalStoragesService,
6972
$logger,
7073
$userSession,
71-
$groupManager
74+
$groupManager,
75+
$config
7276
);
7377
}
7478

@@ -96,6 +100,14 @@ public function create(
96100
$applicableGroups,
97101
$priority
98102
) {
103+
$canCreateNewLocalStorage = $this->config->getSystemValue('files_external_allow_create_new_local', false);
104+
if (!$canCreateNewLocalStorage && $backend === 'local') {
105+
return new DataResponse(
106+
null,
107+
Http::STATUS_FORBIDDEN
108+
);
109+
}
110+
99111
$newStorage = $this->createStorage(
100112
$mountPoint,
101113
$backend,

apps/files_external/lib/Controller/StoragesController.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
use OCP\AppFramework\Http;
4040
use OCP\AppFramework\Http\DataResponse;
4141
use OCP\Files\StorageNotAvailableException;
42+
use OCP\IConfig;
4243
use OCP\IGroupManager;
4344
use OCP\IL10N;
4445
use OCP\ILogger;
@@ -79,6 +80,11 @@ abstract class StoragesController extends Controller {
7980
*/
8081
protected $groupManager;
8182

83+
/**
84+
* @var IConfig
85+
*/
86+
protected $config;
87+
8288
/**
8389
* Creates a new storages controller.
8490
*
@@ -95,14 +101,16 @@ public function __construct(
95101
StoragesService $storagesService,
96102
ILogger $logger,
97103
IUserSession $userSession,
98-
IGroupManager $groupManager
104+
IGroupManager $groupManager,
105+
IConfig $config
99106
) {
100107
parent::__construct($AppName, $request);
101108
$this->l10n = $l10n;
102109
$this->service = $storagesService;
103110
$this->logger = $logger;
104111
$this->userSession = $userSession;
105112
$this->groupManager = $groupManager;
113+
$this->config = $config;
106114
}
107115

108116
/**
@@ -129,6 +137,14 @@ protected function createStorage(
129137
$applicableGroups = null,
130138
$priority = null
131139
) {
140+
$canCreateNewLocalStorage = $this->config->getSystemValue('files_external_allow_create_new_local', false);
141+
if (!$canCreateNewLocalStorage && $backend === 'local') {
142+
return new DataResponse(
143+
null,
144+
Http::STATUS_FORBIDDEN
145+
);
146+
}
147+
132148
try {
133149
return $this->service->createStorage(
134150
$mountPoint,

apps/files_external/lib/Controller/UserGlobalStoragesController.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
use OCA\Files_External\Service\UserGlobalStoragesService;
3737
use OCP\AppFramework\Http;
3838
use OCP\AppFramework\Http\DataResponse;
39+
use OCP\IConfig;
3940
use OCP\IGroupManager;
4041
use OCP\IL10N;
4142
use OCP\ILogger;
@@ -64,7 +65,8 @@ public function __construct(
6465
UserGlobalStoragesService $userGlobalStoragesService,
6566
ILogger $logger,
6667
IUserSession $userSession,
67-
IGroupManager $groupManager
68+
IGroupManager $groupManager,
69+
IConfig $config
6870
) {
6971
parent::__construct(
7072
$AppName,
@@ -73,7 +75,8 @@ public function __construct(
7375
$userGlobalStoragesService,
7476
$logger,
7577
$userSession,
76-
$groupManager
78+
$groupManager,
79+
$config
7780
);
7881
}
7982

apps/files_external/lib/Controller/UserStoragesController.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
use OCA\Files_External\Service\UserStoragesService;
3636
use OCP\AppFramework\Http;
3737
use OCP\AppFramework\Http\DataResponse;
38+
use OCP\IConfig;
3839
use OCP\IGroupManager;
3940
use OCP\IL10N;
4041
use OCP\ILogger;
@@ -63,7 +64,8 @@ public function __construct(
6364
UserStoragesService $userStoragesService,
6465
ILogger $logger,
6566
IUserSession $userSession,
66-
IGroupManager $groupManager
67+
IGroupManager $groupManager,
68+
IConfig $config
6769
) {
6870
parent::__construct(
6971
$AppName,
@@ -72,7 +74,8 @@ public function __construct(
7274
$userStoragesService,
7375
$logger,
7476
$userSession,
75-
$groupManager
77+
$groupManager,
78+
$config
7679
);
7780
}
7881

@@ -127,6 +130,13 @@ public function create(
127130
$backendOptions,
128131
$mountOptions
129132
) {
133+
$canCreateNewLocalStorage = $this->config->getSystemValue('files_external_allow_create_new_local', false);
134+
if (!$canCreateNewLocalStorage && $backend === 'local') {
135+
return new DataResponse(
136+
null,
137+
Http::STATUS_FORBIDDEN
138+
);
139+
}
130140
$newStorage = $this->createStorage(
131141
$mountPoint,
132142
$backend,

apps/files_external/templates/settings.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,10 @@ function writeParameterInput($parameter, $options, $classes = []) {
100100
<h2><?php p($l->t('No external storage configured or you don\'t have the permission to configure them')); ?></h2>
101101
</div>
102102

103-
<form data-can-create="<?php echo $canCreateMounts?'true':'false' ?>" id="files_external" class="section" data-encryption-enabled="<?php echo $_['encryptionEnabled']?'true': 'false'; ?>">
103+
<?php
104+
$canCreateNewLocalStorage = \OC::$server->getConfig()->getSystemValue('files_external_allow_create_new_local', false);
105+
?>
106+
<form data-can-create="<?php echo $canCreateMounts?'true':'false' ?>" data-can-create-local="<?php echo $canCreateNewLocalStorage?'true':'false' ?>" id="files_external" class="section" data-encryption-enabled="<?php echo $_['encryptionEnabled']?'true': 'false'; ?>">
104107
<h2 class="inlineblock" data-anchor-name="external-storage"><?php p($l->t('External storage')); ?></h2>
105108
<a target="_blank" rel="noreferrer" class="icon-info" title="<?php p($l->t('Open documentation'));?>" href="<?php p(link_to_docs('admin-external-storage')); ?>"></a>
106109
<p class="settings-hint"><?php p($l->t('External storage enables you to mount external storage services and devices as secondary Nextcloud storage devices. You may also allow users to mount their own external storage services.')); ?></p>
@@ -150,7 +153,7 @@ function writeParameterInput($parameter, $options, $classes = []) {
150153
});
151154
?>
152155
<?php foreach ($sortedBackends as $backend): ?>
153-
<?php if ($backend->getDeprecateTo()) {
156+
<?php if ($backend->getDeprecateTo() || (!$canCreateNewLocalStorage && $backend->getIdentifier() == "local")) {
154157
continue;
155158
} // ignore deprecated backends?>
156159
<option value="<?php p($backend->getIdentifier()); ?>"><?php p($backend->getText()); ?></option>

apps/files_external/tests/Controller/StoragesControllerTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,12 @@ abstract class StoragesControllerTest extends \Test\TestCase {
5050

5151
protected function setUp(): void {
5252
\OCA\Files_External\MountConfig::$skipTest = true;
53+
\OC::$server->getSystemConfig()->setValue('files_external_allow_create_new_local', true);
5354
}
5455

5556
protected function tearDown(): void {
5657
\OCA\Files_External\MountConfig::$skipTest = false;
58+
\OC::$server->getSystemConfig()->setValue('files_external_allow_create_new_local', false);
5759
}
5860

5961
/**
@@ -130,6 +132,49 @@ public function testAddStorage() {
130132
$this->assertEquals($storageConfig, $data);
131133
}
132134

135+
public function testAddStorageWithoutConfig() {
136+
\OC::$server->getSystemConfig()->setValue('files_external_allow_create_new_local', false);
137+
138+
$authMech = $this->getAuthMechMock();
139+
$authMech->method('validateStorage')
140+
->willReturn(true);
141+
$authMech->method('isVisibleFor')
142+
->willReturn(true);
143+
$backend = $this->getBackendMock();
144+
$backend->method('validateStorage')
145+
->willReturn(true);
146+
$backend->method('isVisibleFor')
147+
->willReturn(true);
148+
149+
$storageConfig = new StorageConfig(1);
150+
$storageConfig->setMountPoint('mount');
151+
$storageConfig->setBackend($backend);
152+
$storageConfig->setAuthMechanism($authMech);
153+
$storageConfig->setBackendOptions([]);
154+
155+
$this->service->expects($this->never())
156+
->method('createStorage')
157+
->will($this->returnValue($storageConfig));
158+
$this->service->expects($this->never())
159+
->method('addStorage')
160+
->will($this->returnValue($storageConfig));
161+
162+
$response = $this->controller->create(
163+
'mount',
164+
'\OCA\Files_External\Lib\Storage\SMB',
165+
'\OCA\Files_External\Lib\Auth\NullMechanism',
166+
[],
167+
[],
168+
[],
169+
[],
170+
null
171+
);
172+
173+
$data = $response->getData();
174+
$this->assertEquals(Http::STATUS_FORBIDDEN, $response->getStatus());
175+
$this->assertEquals(null, $data);
176+
}
177+
133178
public function testUpdateStorage() {
134179
$authMech = $this->getAuthMechMock();
135180
$authMech->method('validateStorage')

config/config.sample.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1746,6 +1746,17 @@
17461746
*/
17471747
'external_storage.auth_availability_delay' => 1800,
17481748

1749+
/**
1750+
* Allows to create external storages of type "Local" in the web interface and APIs.
1751+
*
1752+
* It is still possible to create local storages with occ using the following command:
1753+
* % php occ files_external:create /mountpoint local null::null -c datadir=/path/to/data
1754+
*
1755+
* Defaults to ``false``
1756+
*
1757+
*/
1758+
'files_external_allow_create_new_local' => false,
1759+
17491760
/**
17501761
* Specifies how often the local filesystem (the Nextcloud data/ directory, and
17511762
* NFS mounts in data/) is checked for changes made outside Nextcloud. This

0 commit comments

Comments
 (0)