diff --git a/.drone.yml b/.drone.yml
index dd4ec40420..8d3e3551a6 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -30,6 +30,7 @@ pipeline:
image: nextcloudci/php7.0:php7.0-7
commands:
- ./occ app:check-code admin_audit
+ - ./occ app:check-code bruteforcesettings
- ./occ app:check-code comments
- ./occ app:check-code federation
- ./occ app:check-code sharebymail
diff --git a/.gitignore b/.gitignore
index d8669fed07..1e0f53a3c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,7 +38,7 @@
/apps/files_external/3rdparty/irodsphp/prods/tutorials
/apps/files_external/3rdparty/irodsphp/prods/test*
/apps/files_external/tests/config.*.php
-
+!/apps/bruteforcesettings
# ignore themes except the example and the README
diff --git a/apps/bruteforcesettings/appinfo/info.xml b/apps/bruteforcesettings/appinfo/info.xml
new file mode 100644
index 0000000000..2c3e1256e8
--- /dev/null
+++ b/apps/bruteforcesettings/appinfo/info.xml
@@ -0,0 +1,21 @@
+
+
+ bruteforcesettings
+ Brute force settings
+
+ This applications allows admins to configure the brute force settings.
+
+ AGPL
+ Roeland Jago Douma
+
+ 1.0.0
+
+
+
+
+ BruteForceSettings
+
+
+ OCA\BruteForceSettings\Settings\IPWhitelist
+
+
diff --git a/apps/bruteforcesettings/appinfo/routes.php b/apps/bruteforcesettings/appinfo/routes.php
new file mode 100644
index 0000000000..28ab6e9cee
--- /dev/null
+++ b/apps/bruteforcesettings/appinfo/routes.php
@@ -0,0 +1,30 @@
+
+ *
+ * @author Roeland Jago Douma
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see .
+ *
+ */
+
+return [
+ 'routes' => [
+ [ 'name' => 'IPWhitelist#getAll', 'url' => '/ipwhitelist', 'verb' => 'GET' ],
+ [ 'name' => 'IPWhitelist#add', 'url' => '/ipwhitelist', 'verb' => 'POST' ],
+ [ 'name' => 'IPWhitelist#remove', 'url' => '/ipwhitelist/{id}', 'verb' => 'DELETE' ],
+ ]
+];
diff --git a/apps/bruteforcesettings/js/IPWhitelist.js b/apps/bruteforcesettings/js/IPWhitelist.js
new file mode 100644
index 0000000000..163d5d2852
--- /dev/null
+++ b/apps/bruteforcesettings/js/IPWhitelist.js
@@ -0,0 +1,44 @@
+/**
+ * @copyright 2016, Roeland Jago Douma
+ *
+ * @author Roeland Jago Douma
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see .
+ *
+ */
+
+(function() {
+
+ OCA.BruteForceSettings = OCA.BruteForceSettings || {};
+
+ OCA.BruteForceSettings.WhiteList = {
+
+ collection: null,
+ view: null,
+
+ init: function () {
+ this.collection = new OCA.BruteForceSettings.WhitelistCollection();
+ this.view = new OCA.BruteForceSettings.WhitelistView({
+ collection: this.collection
+ });
+ this.view.reload();
+ }
+ };
+})();
+
+$(document).ready(function() {
+ OCA.BruteForceSettings.WhiteList.init();
+});
diff --git a/apps/bruteforcesettings/js/IPWhitelistCollection.js b/apps/bruteforcesettings/js/IPWhitelistCollection.js
new file mode 100644
index 0000000000..bf5b34d1ad
--- /dev/null
+++ b/apps/bruteforcesettings/js/IPWhitelistCollection.js
@@ -0,0 +1,34 @@
+/**
+ * @copyright 2016, Roeland Jago Douma
+ *
+ * @author Roeland Jago Douma
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see .
+ *
+ */
+
+(function() {
+
+ OCA.BruteForceSettings = OCA.BruteForceSettings || {};
+
+ OCA.BruteForceSettings.WhitelistCollection = OC.Backbone.Collection.extend({
+ model: OCA.BruteForceSettings.WhitelistModel,
+
+ url: function() {
+ return OC.generateUrl('/apps/bruteforcesettings/ipwhitelist');
+ }
+ });
+})();
diff --git a/apps/bruteforcesettings/js/IPWhitelistModel.js b/apps/bruteforcesettings/js/IPWhitelistModel.js
new file mode 100644
index 0000000000..5c309f5af7
--- /dev/null
+++ b/apps/bruteforcesettings/js/IPWhitelistModel.js
@@ -0,0 +1,29 @@
+/**
+ * @copyright 2016, Roeland Jago Douma
+ *
+ * @author Roeland Jago Douma
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see .
+ *
+ */
+
+(function() {
+
+ OCA.BruteForceSettings = OCA.BruteForceSettings || {};
+
+ OCA.BruteForceSettings.WhitelistModel = OC.Backbone.Model.extend({
+ });
+})();
diff --git a/apps/bruteforcesettings/js/IPWhitelistView.js b/apps/bruteforcesettings/js/IPWhitelistView.js
new file mode 100644
index 0000000000..da711ae122
--- /dev/null
+++ b/apps/bruteforcesettings/js/IPWhitelistView.js
@@ -0,0 +1,128 @@
+/**
+ * @copyright 2016, Roeland Jago Douma
+ *
+ * @author Roeland Jago Douma
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see .
+ *
+ */
+
+(function () {
+
+ OCA.BruteForceSettings = OCA.BruteForceSettings || {};
+
+ var TEMPLATE_WHITELIST =
+ '
';
+
+ OCA.BruteForceSettings.WhitelistView = OC.Backbone.View.extend({
+ collection: null,
+
+ ipInput: undefined,
+ maskInput: undefined,
+ submit: undefined,
+
+ list: undefined,
+ listHeader: undefined,
+
+ initialize: function(options) {
+ this.collection = options.collection;
+
+ this.ipInput = $('#whitelist_ip');
+ this.maskInput = $('#whitelist_mask');
+ this.submit = $('#whitelist_submit');
+ this.submit.click(_.bind(this._addWhitelist, this));
+
+ this.list = $('#whitelist-list');
+ this.listHeader = $('#whitelist-list-header');
+
+ this.list.on('click', 'a.icon-delete', _.bind(this._onDeleteRetention, this));
+ this.listenTo(this.collection, 'sync', this.render);
+ },
+
+
+
+ reload: function() {
+ var _this = this;
+ var loadingWhitelists = this.collection.fetch();
+
+ $.when(loadingWhitelists).done(function () {
+ _this.render();
+ });
+ $.when(loadingWhitelists).fail(function () {
+ OC.Notification.showTemporary(t('bruteforcesettings', 'Error while whitelists.'));
+ });
+ },
+
+ template: function (data) {
+ if (_.isUndefined(this._template)) {
+ this._template = Handlebars.compile(TEMPLATE_WHITELIST);
+ }
+
+ return this._template(data);
+ },
+
+ render: function () {
+ var _this = this;
+ this.list.html('');
+
+ this.collection.forEach(function (model) {
+ var data = {
+ id: model.attributes.id,
+ ip: model.attributes.ip,
+ mask: model.attributes.mask
+ };
+ var html = _this.template(data);
+ var $html = $(html);
+ _this.list.append($html);
+ });
+ },
+
+ _onDeleteRetention: function(event) {
+ var $target = $(event.target);
+ var $row = $target.closest('tr');
+ var id = $row.data('id');
+
+ var whitelist = this.collection.get(id);
+
+ if (_.isUndefined(whitelist)) {
+ // Ignore event
+ return;
+ }
+
+ var destroyingRetention = whitelist.destroy();
+
+ $row.find('.icon-delete').tooltip('hide');
+
+ var _this = this;
+ $.when(destroyingRetention).fail(function () {
+ OC.Notification.showTemporary(t('bruteforcesettings', 'Error while deleting a whitelist'));
+ });
+ $.when(destroyingRetention).always(function () {
+ _this.render();
+ });
+ },
+
+ _addWhitelist: function() {
+ this.collection.create({
+ ip: this.ipInput.val(),
+ mask: this.maskInput.val()
+ });
+ }
+ });
+})();
diff --git a/apps/bruteforcesettings/lib/Controller/IPWhitelistController.php b/apps/bruteforcesettings/lib/Controller/IPWhitelistController.php
new file mode 100644
index 0000000000..9b5183f749
--- /dev/null
+++ b/apps/bruteforcesettings/lib/Controller/IPWhitelistController.php
@@ -0,0 +1,123 @@
+
+ *
+ * @author Roeland Jago Douma
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see .
+ *
+ */
+
+namespace OCA\BruteForceSettings\Controller;
+
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\JSONResponse;
+use OCP\IConfig;
+use OCP\IRequest;
+
+class IPWhitelistController extends Controller {
+
+ /** @var IConfig */
+ private $config;
+
+ /**
+ * IPWhitelistController constructor.
+ *
+ * @param string $appName
+ * @param IRequest $request
+ * @param IConfig $config
+ */
+ public function __construct($appName,
+ IRequest $request,
+ IConfig $config) {
+ parent::__construct($appName, $request);
+
+ $this->config = $config;
+ }
+
+ /**
+ * @return JSONResponse
+ */
+ public function getAll() {
+ $keys = $this->config->getAppKeys('bruteForce');
+ $keys = array_filter($keys, function($key) {
+ $regex = '/^whitelist_/S';
+ return preg_match($regex, $key) === 1;
+ });
+
+ $result = [];
+
+ foreach ($keys as $key) {
+ $value = $this->config->getAppValue('bruteForce', $key);
+ $values = explode('/', $value);
+
+ $result[] = [
+ 'id' => (int)substr($key, 10),
+ 'ip' => $values[0],
+ 'mask' => $values[1],
+ ];
+ }
+
+ return new JSONResponse($result);
+ }
+
+ /**
+ * @param string $ip
+ * @param int $mask
+ * @return JSONResponse
+ */
+ public function add($ip, $mask) {
+ if (!filter_var($ip, FILTER_VALIDATE_IP) ||
+ (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) && ($mask < 0 || $mask > 32)) ||
+ (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) && ($mask < 0 || $mask > 128))) {
+ return new JSONResponse([], Http::STATUS_BAD_REQUEST);
+ }
+
+ $keys = $this->config->getAppKeys('bruteForce');
+ $keys = array_filter($keys, function($key) {
+ $regex = '/^whitelist_/S';
+ return preg_match($regex, $key) === 1;
+ });
+
+ $id = 0;
+ foreach ($keys as $key) {
+ $tmp = (int)substr($key, 10);
+ if ($tmp > $id) {
+ $id = $tmp;
+ }
+ }
+ $id++;
+
+ $value = $ip . '/' . $mask;
+ $this->config->setAppValue('bruteForce', 'whitelist_'.$id, $value);
+ return new JSONResponse([
+ 'id' => $id,
+ 'ip' => $ip,
+ 'mask' => $mask,
+ ]);
+ }
+
+ /**
+ * @param int $id
+ * @return JSONResponse
+ */
+ public function remove($id) {
+ $this->config->deleteAppValue('bruteForce', 'whitelist_'.$id);
+
+ return new JSONResponse([]);
+ }
+}
diff --git a/apps/bruteforcesettings/lib/Settings/IPWhitelist.php b/apps/bruteforcesettings/lib/Settings/IPWhitelist.php
new file mode 100644
index 0000000000..7e4aab2f22
--- /dev/null
+++ b/apps/bruteforcesettings/lib/Settings/IPWhitelist.php
@@ -0,0 +1,42 @@
+
+ *
+ * @author Roeland Jago Douma
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see .
+ *
+ */
+
+namespace OCA\BruteForceSettings\Settings;
+
+use OCP\AppFramework\Http\TemplateResponse;
+use OCP\Settings\ISettings;
+
+class IPWhitelist implements ISettings {
+
+ public function getForm() {
+ return new TemplateResponse('bruteforcesettings', 'ipwhitelist');
+ }
+
+ public function getSection() {
+ return 'security';
+ }
+
+ public function getPriority() {
+ return 50;
+ }
+}
diff --git a/apps/bruteforcesettings/templates/ipwhitelist.php b/apps/bruteforcesettings/templates/ipwhitelist.php
new file mode 100644
index 0000000000..6935495616
--- /dev/null
+++ b/apps/bruteforcesettings/templates/ipwhitelist.php
@@ -0,0 +1,48 @@
+
+ *
+ * @author Roeland Jago Douma
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see .
+ *
+ */
+
+script('core', [
+ 'oc-backbone-webdav',
+]);
+script('bruteforcesettings', [
+ 'IPWhitelist',
+ 'IPWhitelistModel',
+ 'IPWhitelistCollection',
+ 'IPWhitelistView',
+]);
+
+/** @var \OCP\IL10N $l */
+?>
+
diff --git a/apps/bruteforcesettings/tests/Controller/IPWhitelistControllerTest.php b/apps/bruteforcesettings/tests/Controller/IPWhitelistControllerTest.php
new file mode 100644
index 0000000000..c45fc6a941
--- /dev/null
+++ b/apps/bruteforcesettings/tests/Controller/IPWhitelistControllerTest.php
@@ -0,0 +1,151 @@
+
+ *
+ * @author Roeland Jago Douma
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see .
+ *
+ */
+
+namespace OCA\BruteForceSettings\Tests\Controller;
+
+use OCA\BruteForceSettings\Controller\IPWhitelistController;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\JSONResponse;
+use OCP\IConfig;
+use OCP\IRequest;
+use Test\TestCase;
+
+class IPWhitelistControllerTest extends TestCase {
+
+ /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
+ private $config;
+ /** @var IPWhitelistController */
+ private $controller;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->config = $this->createMock(IConfig::class);
+ $this->controller = new IPWhitelistController(
+ 'bruteforce',
+ $this->createMock(IRequest::class),
+ $this->config
+ );
+ }
+
+ public function testGetAll() {
+ $this->config->method('getAppKeys')
+ ->with($this->equalTo('bruteForce'))
+ ->willReturn([
+ 'foobar',
+ 'whitelist_0',
+ 'whitelist_99',
+ ]);
+
+ $this->config->method('getAppValue')
+ ->will($this->returnCallback(function($app, $key) {
+ if ($app !== 'bruteForce') {
+ $this->fail();
+ }
+ if ($key === 'whitelist_0') {
+ return '192.168.2.0/24';
+ } else if ($key === 'whitelist_99') {
+ return 'dead:beef:cafe::/92';
+ }
+ $this->fail();
+ }));
+
+ $expected = new JSONResponse([
+ [
+ 'id' => 0,
+ 'ip' => '192.168.2.0',
+ 'mask' => '24',
+ ],
+ [
+ 'id' => 99,
+ 'ip' => 'dead:beef:cafe::',
+ 'mask' => '92',
+ ]
+ ]);
+
+ $this->assertEquals($expected, $this->controller->getAll());
+ }
+
+ public function dataAdd() {
+ return [
+ ['8.500.2.3', 24, false],
+ ['1.2.3.4', 24, true],
+ ['1.2.3.4', -1, false],
+ ['1.2.3.4', 33, false],
+
+ ['dead:nope::8', 24, false],
+ ['1234:567:abef::1a2b', 24, true],
+ ['1234:567:abef::1a2b', -1, false],
+ ['1234:567:abef::1a2b', 129, false],
+ ];
+ }
+
+ /**
+ * @dataProvider dataAdd
+ *
+ * @param string $ip
+ * @param int $mask
+ * @param bool $valid
+ */
+ public function testAdd($ip, $mask, $valid) {
+ if (!$valid) {
+ $expected = new JSONResponse([], Http::STATUS_BAD_REQUEST);
+ } else {
+ $this->config->method('getAppKeys')
+ ->with($this->equalTo('bruteForce'))
+ ->willReturn([
+ 'foobar',
+ 'whitelist_0',
+ 'whitelist_99',
+ ]);
+
+ $this->config->expects($this->once())
+ ->method('setAppValue')
+ ->with(
+ $this->equalTo('bruteForce'),
+ $this->equalTo('whitelist_100'),
+ $this->equalTo($ip.'/'.$mask)
+ );
+
+ $expected = new JSONResponse([
+ 'id' => 100,
+ 'ip' => $ip,
+ 'mask' => $mask,
+ ]);
+ }
+
+ $this->assertEquals($expected, $this->controller->add($ip, $mask));
+ }
+
+ public function testRemove() {
+ $this->config->expects($this->once())
+ ->method('deleteAppValue')
+ ->with(
+ $this->equalTo('bruteForce'),
+ $this->equalTo('whitelist_42')
+ );
+
+ $expected = new JSONResponse([]);
+ $this->assertEquals($expected, $this->controller->remove(42));
+ }
+}
diff --git a/apps/bruteforcesettings/tests/Settings/IPWhitelistTest.php b/apps/bruteforcesettings/tests/Settings/IPWhitelistTest.php
new file mode 100644
index 0000000000..37d13a86d5
--- /dev/null
+++ b/apps/bruteforcesettings/tests/Settings/IPWhitelistTest.php
@@ -0,0 +1,33 @@
+settings = new IPWhitelist();
+ }
+
+ public function testGetForm() {
+ $expected = new TemplateResponse('bruteforcesettings', 'ipwhitelist');
+
+ $this->assertEquals($expected, $this->settings->getForm());
+ }
+
+ public function testGetSection() {
+ $this->assertSame('security', $this->settings->getSection());
+ }
+
+ public function testGetPriority() {
+ $this->assertSame(50, $this->settings->getPriority());
+ }
+}
diff --git a/apps/bruteforcesettings/tests/js/IPWhitelistSpec.js b/apps/bruteforcesettings/tests/js/IPWhitelistSpec.js
new file mode 100644
index 0000000000..21ba32faa3
--- /dev/null
+++ b/apps/bruteforcesettings/tests/js/IPWhitelistSpec.js
@@ -0,0 +1,174 @@
+/**
+ * @copyright 2016, Roeland Jago Douma
+ *
+ * @author Roeland Jago Douma
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see .
+ *
+ */
+
+describe('OCA.BruteForceSettings.IPWhiteList tests', function() {
+ beforeEach(function() {
+ // init parameters and test table elements
+ $('#testArea').append(
+ '