From c7aef6c36833b1d9bdec9dc30ceb874b8cb93019 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 26 Aug 2015 17:08:25 +0200 Subject: [PATCH 1/3] Fix uploading avatar and root certs in IE8 --- core/avatar/avatarcontroller.php | 58 +++++++++++++++---- core/js/js.js | 1 + lib/public/appframework/controller.php | 8 ++- lib/public/util.php | 14 +++++ settings/controller/certificatecontroller.php | 19 ++++-- settings/js/personal.js | 46 +++++++++++---- settings/personal.php | 1 + settings/templates/personal.php | 11 ++-- 8 files changed, 124 insertions(+), 34 deletions(-) diff --git a/core/avatar/avatarcontroller.php b/core/avatar/avatarcontroller.php index 4841ba00f7..1604ecf79d 100644 --- a/core/avatar/avatarcontroller.php +++ b/core/avatar/avatarcontroller.php @@ -140,12 +140,21 @@ class AvatarController extends Controller { $userId = $this->userSession->getUser()->getUID(); $files = $this->request->getUploadedFile('files'); + $headers = []; + if (\OCP\Util::isIE8()) { + // due to upload iframe workaround, need to set content-type to text/plain + $headers['Content-Type'] = 'text/plain'; + } + if (isset($path)) { $path = stripslashes($path); $node = $this->userFolder->get($path); if ($node->getSize() > 20*1024*1024) { - return new DataResponse(['data' => ['message' => $this->l->t('File is too big')]], - Http::STATUS_BAD_REQUEST); + return new DataResponse( + ['data' => ['message' => $this->l->t('File is too big')]], + Http::STATUS_BAD_REQUEST, + $headers + ); } $content = $node->getContent(); } elseif (!is_null($files)) { @@ -155,20 +164,29 @@ class AvatarController extends Controller { !\OC\Files\Filesystem::isFileBlacklisted($files['tmp_name'][0]) ) { if ($files['size'][0] > 20*1024*1024) { - return new DataResponse(['data' => ['message' => $this->l->t('File is too big')]], - Http::STATUS_BAD_REQUEST); + return new DataResponse( + ['data' => ['message' => $this->l->t('File is too big')]], + Http::STATUS_BAD_REQUEST, + $headers + ); } $this->cache->set('avatar_upload', file_get_contents($files['tmp_name'][0]), 7200); $content = $this->cache->get('avatar_upload'); unlink($files['tmp_name'][0]); } else { - return new DataResponse(['data' => ['message' => $this->l->t('Invalid file provided')]], - Http::STATUS_BAD_REQUEST); + return new DataResponse( + ['data' => ['message' => $this->l->t('Invalid file provided')]], + Http::STATUS_BAD_REQUEST, + $headers + ); } } else { //Add imgfile - return new DataResponse(['data' => ['message' => $this->l->t('No image or file provided')]], - Http::STATUS_BAD_REQUEST); + return new DataResponse( + ['data' => ['message' => $this->l->t('No image or file provided')]], + Http::STATUS_BAD_REQUEST, + $headers + ); } try { @@ -179,16 +197,32 @@ class AvatarController extends Controller { if ($image->valid()) { $mimeType = $image->mimeType(); if ($mimeType !== 'image/jpeg' && $mimeType !== 'image/png') { - return new DataResponse(['data' => ['message' => $this->l->t('Unknown filetype')]]); + return new DataResponse( + ['data' => ['message' => $this->l->t('Unknown filetype')]], + Http::STATUS_OK, + $headers + ); } $this->cache->set('tmpAvatar', $image->data(), 7200); - return new DataResponse(['data' => 'notsquare']); + return new DataResponse( + ['data' => 'notsquare'], + Http::STATUS_OK, + $headers + ); } else { - return new DataResponse(['data' => ['message' => $this->l->t('Invalid image')]]); + return new DataResponse( + ['data' => ['message' => $this->l->t('Invalid image')]], + Http::STATUS_OK, + $headers + ); } } catch (\Exception $e) { - return new DataResponse(['data' => ['message' => $e->getMessage()]]); + return new DataResponse( + ['data' => ['message' => $e->getMessage()]], + Http::STATUS_OK, + $headers + ); } } diff --git a/core/js/js.js b/core/js/js.js index 4f0f288bd0..00a775b802 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -85,6 +85,7 @@ var OC={ appConfig: window.oc_appconfig || {}, theme: window.oc_defaults || {}, coreApps:['', 'admin','log','core/search','settings','core','3rdparty'], + requestToken: oc_requesttoken, menuSpeed: 50, /** diff --git a/lib/public/appframework/controller.php b/lib/public/appframework/controller.php index b8986c0b77..5c7292cd13 100644 --- a/lib/public/appframework/controller.php +++ b/lib/public/appframework/controller.php @@ -83,7 +83,13 @@ abstract class Controller { $data->getData(), $data->getStatus() ); - $response->setHeaders(array_merge($data->getHeaders(), $response->getHeaders())); + $dataHeaders = $data->getHeaders(); + $headers = $response->getHeaders(); + // do not overwrite Content-Type if it already exists + if (isset($dataHeaders['Content-Type'])) { + unset($headers['Content-Type']); + } + $response->setHeaders(array_merge($dataHeaders, $headers)); return $response; } else { return new JSONResponse($data); diff --git a/lib/public/util.php b/lib/public/util.php index 76b61347d4..2b81b6bfc4 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -670,4 +670,18 @@ class Util { } return self::$needUpgradeCache; } + + /** + * Returns whether the current request is coming from a + * famous awfully old browser. + * + * @return boolean true if it's IE8, false otherwise + */ + public static function isIE8() { + preg_match('/MSIE (.*?);/', $_SERVER['HTTP_USER_AGENT'], $matches); + if (count($matches) > 0 && $matches[1] <= 9) { + return true; + } + return false; + } } diff --git a/settings/controller/certificatecontroller.php b/settings/controller/certificatecontroller.php index 8ff9f51a66..b7bc81920c 100644 --- a/settings/controller/certificatecontroller.php +++ b/settings/controller/certificatecontroller.php @@ -68,19 +68,25 @@ class CertificateController extends Controller { * @return array */ public function addPersonalRootCertificate() { + $headers = []; + if (\OCP\Util::isIE8()) { + // due to upload iframe workaround, need to set content-type to text/plain + $headers['Content-Type'] = 'text/plain'; + } if ($this->isCertificateImportAllowed() === false) { - return new DataResponse('Individual certificate management disabled', Http::STATUS_FORBIDDEN); + return new DataResponse(['message' => 'Individual certificate management disabled'], Http::STATUS_FORBIDDEN, $headers); } $file = $this->request->getUploadedFile('rootcert_import'); if(empty($file)) { - return new DataResponse(['message' => 'No file uploaded'], Http::STATUS_UNPROCESSABLE_ENTITY); + return new DataResponse(['message' => 'No file uploaded'], Http::STATUS_UNPROCESSABLE_ENTITY, $headers); } try { $certificate = $this->certificateManager->addCertificate(file_get_contents($file['tmp_name']), $file['name']); - return new DataResponse([ + return new DataResponse( + [ 'name' => $certificate->getName(), 'commonName' => $certificate->getCommonName(), 'organization' => $certificate->getOrganization(), @@ -90,9 +96,12 @@ class CertificateController extends Controller { 'validTillString' => $this->l10n->l('date', $certificate->getExpireDate()), 'issuer' => $certificate->getIssuerName(), 'issuerOrganization' => $certificate->getIssuerOrganization(), - ]); + ], + Http::STATUS_OK, + $headers + ); } catch (\Exception $e) { - return new DataResponse('An error occurred.', Http::STATUS_UNPROCESSABLE_ENTITY); + return new DataResponse('An error occurred.', Http::STATUS_UNPROCESSABLE_ENTITY, $headers); } } diff --git a/settings/js/personal.js b/settings/js/personal.js index 33746d22ac..acc1478cd7 100644 --- a/settings/js/personal.js +++ b/settings/js/personal.js @@ -5,8 +5,6 @@ * See the COPYING-README file. */ -/* global OC, t */ - /** * The callback will be fired as soon as enter is pressed by the * user or 1 second after the last data entry @@ -156,6 +154,9 @@ function cleanCropper () { } function avatarResponseHandler (data) { + if (typeof data === 'string') { + data = $.parseJSON(data); + } var $warning = $('#avatar .warning'); $warning.hide(); if (data.status === "success") { @@ -233,7 +234,21 @@ $(document).ready(function () { var uploadparms = { done: function (e, data) { - avatarResponseHandler(data.result); + var response = data; + if (typeof data.result === 'string') { + response = $.parseJSON(data.result); + } else if (data.result && data.result.length) { + // fetch response from iframe + response = $.parseJSON(data.result[0].body.innerText); + } else { + response = data.result; + } + avatarResponseHandler(response); + }, + submit: function(e, data) { + data.formData = _.extend(data.formData || {}, { + requesttoken: OC.requestToken + }); }, fail: function (e, data){ var msg = data.jqXHR.statusText + ' (' + data.jqXHR.status + ')'; @@ -251,10 +266,6 @@ $(document).ready(function () { } }; - $('#uploadavatarbutton').click(function () { - $('#uploadavatar').click(); - }); - $('#uploadavatar').fileupload(uploadparms); $('#selectavatar').click(function () { @@ -344,7 +355,24 @@ $(document).ready(function () { $('#sslCertificate tr > td').tipsy({gravity: 'n', live: true}); $('#rootcert_import').fileupload({ + submit: function(e, data) { + data.formData = _.extend(data.formData || {}, { + requesttoken: OC.requestToken + }); + }, success: function (data) { + if (typeof data === 'string') { + data = $.parseJSON(data); + } else if (data && data.length) { + // fetch response from iframe + data = $.parseJSON(data[0].body.innerText); + } + if (!data || typeof(data) === 'string') { + // IE8 iframe workaround comes here instead of fail() + OC.Notification.showTemporary( + t('settings', 'An error occurred. Please upload an ASCII-encoded PEM certificate.')); + return; + } var issueDate = new Date(data.validFrom * 1000); var expireDate = new Date(data.validTill * 1000); var now = new Date(); @@ -374,10 +402,6 @@ $(document).ready(function () { } }); - $('#rootcert_import_button').click(function () { - $('#rootcert_import').click(); - }); - if ($('#sslCertificate > tbody > tr').length === 0) { $('#sslCertificate').hide(); } diff --git a/settings/personal.php b/settings/personal.php index e58e043af5..8cbcf923a5 100644 --- a/settings/personal.php +++ b/settings/personal.php @@ -46,6 +46,7 @@ OC_Util::addScript( 'settings', 'personal' ); OC_Util::addStyle( 'settings', 'settings' ); \OC_Util::addVendorScript('strengthify/jquery.strengthify'); \OC_Util::addVendorStyle('strengthify/strengthify'); +\OC_Util::addScript('files', 'jquery.iframe-transport'); \OC_Util::addScript('files', 'jquery.fileupload'); if ($config->getSystemValue('enable_avatars', true) === true) { \OC_Util::addVendorScript('jcrop/js/jquery.Jcrop'); diff --git a/settings/templates/personal.php b/settings/templates/personal.php index c0adaf9c5a..0eba71d77d 100644 --- a/settings/templates/personal.php +++ b/settings/templates/personal.php @@ -155,10 +155,11 @@ if($_['passwordChangeSupported']) {

-
t('Upload new')); ?>
- +
t('Select new from Files')); ?>
-
t('Remove image')); ?>

+
t('Remove image')); ?>
+ +
t('Either png or jpg. Ideally square but you will be able to crop it. The file is not allowed to exceed the maximum size of 20 MB.')); ?> t('Your avatar is provided by your original account.')); ?> @@ -239,8 +240,8 @@ if($_['passwordChangeSupported']) {
- - + +
From bf579a153f8f0d6fb081a1d11718ea48c779da34 Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Tue, 6 Oct 2015 14:58:07 +0200 Subject: [PATCH 2/3] fix IE8 user agent detection --- core/avatar/avatarcontroller.php | 2 +- lib/private/appframework/http/request.php | 1 + lib/public/util.php | 14 -------------- settings/controller/certificatecontroller.php | 2 +- 4 files changed, 3 insertions(+), 16 deletions(-) diff --git a/core/avatar/avatarcontroller.php b/core/avatar/avatarcontroller.php index 1604ecf79d..eb2cb65710 100644 --- a/core/avatar/avatarcontroller.php +++ b/core/avatar/avatarcontroller.php @@ -141,7 +141,7 @@ class AvatarController extends Controller { $files = $this->request->getUploadedFile('files'); $headers = []; - if (\OCP\Util::isIE8()) { + if (\OC::$server->getRequest()->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE_8])) { // due to upload iframe workaround, need to set content-type to text/plain $headers['Content-Type'] = 'text/plain'; } diff --git a/lib/private/appframework/http/request.php b/lib/private/appframework/http/request.php index 3e24eec37c..7778513516 100644 --- a/lib/private/appframework/http/request.php +++ b/lib/private/appframework/http/request.php @@ -43,6 +43,7 @@ use OCP\Security\ISecureRandom; class Request implements \ArrayAccess, \Countable, IRequest { const USER_AGENT_IE = '/MSIE/'; + const USER_AGENT_IE_8 = '/MSIE 8.0/'; // Android Chrome user agent: https://developers.google.com/chrome/mobile/docs/user-agent const USER_AGENT_ANDROID_MOBILE_CHROME = '#Android.*Chrome/[.0-9]*#'; const USER_AGENT_FREEBOX = '#^Mozilla/5\.0$#'; diff --git a/lib/public/util.php b/lib/public/util.php index 2b81b6bfc4..76b61347d4 100644 --- a/lib/public/util.php +++ b/lib/public/util.php @@ -670,18 +670,4 @@ class Util { } return self::$needUpgradeCache; } - - /** - * Returns whether the current request is coming from a - * famous awfully old browser. - * - * @return boolean true if it's IE8, false otherwise - */ - public static function isIE8() { - preg_match('/MSIE (.*?);/', $_SERVER['HTTP_USER_AGENT'], $matches); - if (count($matches) > 0 && $matches[1] <= 9) { - return true; - } - return false; - } } diff --git a/settings/controller/certificatecontroller.php b/settings/controller/certificatecontroller.php index b7bc81920c..ef14ff3d9d 100644 --- a/settings/controller/certificatecontroller.php +++ b/settings/controller/certificatecontroller.php @@ -69,7 +69,7 @@ class CertificateController extends Controller { */ public function addPersonalRootCertificate() { $headers = []; - if (\OCP\Util::isIE8()) { + if (\OC::$server->getRequest()->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE_8])) { // due to upload iframe workaround, need to set content-type to text/plain $headers['Content-Type'] = 'text/plain'; } From 14591d9df70ed453b911b5c6647cb2fd20cf5be5 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 7 Oct 2015 11:13:47 +0200 Subject: [PATCH 3/3] Use injected request --- core/avatar/avatarcontroller.php | 2 +- settings/controller/certificatecontroller.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/avatar/avatarcontroller.php b/core/avatar/avatarcontroller.php index eb2cb65710..97b3615c03 100644 --- a/core/avatar/avatarcontroller.php +++ b/core/avatar/avatarcontroller.php @@ -141,7 +141,7 @@ class AvatarController extends Controller { $files = $this->request->getUploadedFile('files'); $headers = []; - if (\OC::$server->getRequest()->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE_8])) { + if ($this->request->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE_8])) { // due to upload iframe workaround, need to set content-type to text/plain $headers['Content-Type'] = 'text/plain'; } diff --git a/settings/controller/certificatecontroller.php b/settings/controller/certificatecontroller.php index ef14ff3d9d..750144e7a2 100644 --- a/settings/controller/certificatecontroller.php +++ b/settings/controller/certificatecontroller.php @@ -69,7 +69,7 @@ class CertificateController extends Controller { */ public function addPersonalRootCertificate() { $headers = []; - if (\OC::$server->getRequest()->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE_8])) { + if ($this->request->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE_8])) { // due to upload iframe workaround, need to set content-type to text/plain $headers['Content-Type'] = 'text/plain'; }