aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulius Härtl <jus@bitgrid.net>2019-07-31 10:05:46 +0200
committerJulius Härtl <jus@bitgrid.net>2019-07-31 10:20:57 +0200
commit47a0254bb372cf68626302175d2e5f9d0c10e73b (patch)
tree4e7c87c80007e7a9ed863b7d18866fb2b283c061
parent3f8f0f76091bf0f0fae7e602f14a3a5f225f111b (diff)
downloadnextcloud-server-47a0254bb372cf68626302175d2e5f9d0c10e73b.tar.gz
nextcloud-server-47a0254bb372cf68626302175d2e5f9d0c10e73b.zip
Validate urls in theming settings and properly handle error messages
Signed-off-by: Julius Härtl <jus@bitgrid.net>
-rw-r--r--apps/theming/js/settings-admin.js6
-rw-r--r--apps/theming/lib/Controller/ThemingController.php68
-rw-r--r--apps/theming/tests/Controller/ThemingControllerTest.php18
3 files changed, 49 insertions, 43 deletions
diff --git a/apps/theming/js/settings-admin.js b/apps/theming/js/settings-admin.js
index af9c584265c..81b10bcc08e 100644
--- a/apps/theming/js/settings-admin.js
+++ b/apps/theming/js/settings-admin.js
@@ -32,7 +32,7 @@ function setThemingValue(setting, value) {
hideUndoButton(setting, value);
preview(setting, value, response.data.serverCssUrl);
}).fail(function(response) {
- OC.msg.finishedSaving('#theming_settings_msg', response);
+ OC.msg.finishedSaving('#theming_settings_msg', response.responseJSON);
$('#theming_settings_loading').hide();
});
}
@@ -159,7 +159,7 @@ $(document).ready(function () {
return true;
} else {
throw t('theming', 'Name cannot be empty');
- }
+ }
} catch (error) {
$('#theming-name').attr('title', error);
$('#theming-name').tooltip({placement: 'top', trigger: 'manual'});
@@ -174,7 +174,7 @@ $(document).ready(function () {
if (checkName()) {
$('#theming-name').tooltip('hide');
$('#theming-name').removeClass('error');
- }
+ }
});
$('#theming-name').change(function(e) {
diff --git a/apps/theming/lib/Controller/ThemingController.php b/apps/theming/lib/Controller/ThemingController.php
index cc8af2cae3e..47895335640 100644
--- a/apps/theming/lib/Controller/ThemingController.php
+++ b/apps/theming/lib/Controller/ThemingController.php
@@ -135,68 +135,56 @@ class ThemingController extends Controller {
*/
public function updateStylesheet($setting, $value) {
$value = trim($value);
+ $error = null;
switch ($setting) {
case 'name':
if (strlen($value) > 250) {
- return new DataResponse([
- 'data' => [
- 'message' => $this->l10n->t('The given name is too long'),
- ],
- 'status' => 'error'
- ]);
+ $error = $this->l10n->t('The given name is too long');
}
break;
case 'url':
if (strlen($value) > 500) {
- return new DataResponse([
- 'data' => [
- 'message' => $this->l10n->t('The given web address is too long'),
- ],
- 'status' => 'error'
- ]);
+ $error = $this->l10n->t('The given web address is too long');
+ }
+ if (!$this->isValidUrl($value)) {
+ $error = $this->l10n->t('The given web address is not a valid URL');
}
break;
case 'imprintUrl':
if (strlen($value) > 500) {
- return new DataResponse([
- 'data' => [
- 'message' => $this->l10n->t('The given legal notice address is too long'),
- ],
- 'status' => 'error'
- ]);
+ $error = $this->l10n->t('The given legal notice address is too long');
+ }
+ if (!$this->isValidUrl($value)) {
+ $error = $this->l10n->t('The given legal notice address is not a valid URL');
}
break;
case 'privacyUrl':
if (strlen($value) > 500) {
- return new DataResponse([
- 'data' => [
- 'message' => $this->l10n->t('The given privacy policy address is too long'),
- ],
- 'status' => 'error'
- ]);
+ $error = $this->l10n->t('The given privacy policy address is too long');
+ }
+ if (!$this->isValidUrl($value)) {
+ $error = $this->l10n->t('The given privacy policy address is not a valid URL');
}
break;
case 'slogan':
if (strlen($value) > 500) {
- return new DataResponse([
- 'data' => [
- 'message' => $this->l10n->t('The given slogan is too long'),
- ],
- 'status' => 'error'
- ]);
+ $error = $this->l10n->t('The given slogan is too long');
}
break;
case 'color':
if (!preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $value)) {
- return new DataResponse([
- 'data' => [
- 'message' => $this->l10n->t('The given color is invalid'),
- ],
- 'status' => 'error'
- ]);
+ $error = $this->l10n->t('The given color is invalid');
}
break;
}
+ if ($error !== null) {
+ return new DataResponse([
+ 'data' => [
+ 'message' => $error,
+ ],
+ 'status' => 'error'
+ ], Http::STATUS_BAD_REQUEST);
+ }
$this->themingDefaults->set($setting, $value);
@@ -216,6 +204,14 @@ class ThemingController extends Controller {
}
/**
+ * Check that a string is a valid http/https url
+ */
+ private function isValidUrl(string $url): bool {
+ return ((strpos($url, 'http://') === 0 || strpos($url, 'https://') === 0) &&
+ filter_var($url, FILTER_VALIDATE_URL) !== false);
+ }
+
+ /**
* @return DataResponse
* @throws NotPermittedException
*/
diff --git a/apps/theming/tests/Controller/ThemingControllerTest.php b/apps/theming/tests/Controller/ThemingControllerTest.php
index 457e9900b5e..93a1e040b4b 100644
--- a/apps/theming/tests/Controller/ThemingControllerTest.php
+++ b/apps/theming/tests/Controller/ThemingControllerTest.php
@@ -123,10 +123,13 @@ class ThemingControllerTest extends TestCase {
public function dataUpdateStylesheetSuccess() {
return [
['name', str_repeat('a', 250), 'Saved'],
- ['url', str_repeat('a', 500), 'Saved'],
+ ['url', 'https://nextcloud.com/' . str_repeat('a', 478), 'Saved'],
['slogan', str_repeat('a', 500), 'Saved'],
['color', '#0082c9', 'Saved'],
['color', '#0082C9', 'Saved'],
+ ['color', '#0082C9', 'Saved'],
+ ['imprintUrl', 'https://nextcloud.com/' . str_repeat('a', 478), 'Saved'],
+ ['privacyUrl', 'https://nextcloud.com/' . str_repeat('a', 478), 'Saved'],
];
}
@@ -175,11 +178,17 @@ class ThemingControllerTest extends TestCase {
public function dataUpdateStylesheetError() {
return [
['name', str_repeat('a', 251), 'The given name is too long'],
- ['url', str_repeat('a', 501), 'The given web address is too long'],
+ ['url', 'http://example.com/' . str_repeat('a', 501), 'The given web address is too long'],
+ ['url', str_repeat('a', 501), 'The given web address is not a valid URL'],
+ ['url', 'javascript:alert(1)', 'The given web address is not a valid URL'],
['slogan', str_repeat('a', 501), 'The given slogan is too long'],
['color', '0082C9', 'The given color is invalid'],
['color', '#0082Z9', 'The given color is invalid'],
['color', 'Nextcloud', 'The given color is invalid'],
+ ['imprintUrl', '0082C9', 'The given legal notice address is not a valid URL'],
+ ['imprintUrl', '0082C9', 'The given legal notice address is not a valid URL'],
+ ['imprintUrl', 'javascript:foo', 'The given legal notice address is not a valid URL'],
+ ['privacyUrl', '#0082Z9', 'The given privacy policy address is not a valid URL'],
];
}
@@ -196,7 +205,7 @@ class ThemingControllerTest extends TestCase {
->method('set')
->with($setting, $value);
$this->l10n
- ->expects($this->once())
+ ->expects($this->any())
->method('t')
->will($this->returnCallback(function($str) {
return $str;
@@ -209,7 +218,8 @@ class ThemingControllerTest extends TestCase {
'message' => $message,
],
'status' => 'error',
- ]
+ ],
+ Http::STATUS_BAD_REQUEST
);
$this->assertEquals($expected, $this->themingController->updateStylesheet($setting, $value));
}