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();
});
}
return true;
} else {
throw t('theming', 'Name cannot be empty');
- }
+ }
} catch (error) {
$('#theming-name').attr('title', error);
$('#theming-name').tooltip({placement: 'top', trigger: 'manual'});
if (checkName()) {
$('#theming-name').tooltip('hide');
$('#theming-name').removeClass('error');
- }
+ }
});
$('#theming-name').change(function(e) {
*/
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);
);
}
+ /**
+ * 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
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'],
];
}
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'],
];
}
->method('set')
->with($setting, $value);
$this->l10n
- ->expects($this->once())
+ ->expects($this->any())
->method('t')
->will($this->returnCallback(function($str) {
return $str;
'message' => $message,
],
'status' => 'error',
- ]
+ ],
+ Http::STATUS_BAD_REQUEST
);
$this->assertEquals($expected, $this->themingController->updateStylesheet($setting, $value));
}