From 4a47796781e88e984903ac10529aa15ff4d0b059 Mon Sep 17 00:00:00 2001 From: RainLoop Team Date: Wed, 14 May 2014 03:08:27 +0400 Subject: [PATCH] ownCloud Integration App (#144) + external sso functionality --- Gruntfile.js | 51 +++++- build/owncloud/rainloop-app/INSTALL | 29 +++ build/owncloud/rainloop-app/admin.php | 19 ++ build/owncloud/rainloop-app/ajax/admin.php | 33 ++++ build/owncloud/rainloop-app/ajax/personal.php | 45 +++++ build/owncloud/rainloop-app/appinfo/app.php | 23 +++ build/owncloud/rainloop-app/appinfo/info.xml | 10 ++ .../owncloud/rainloop-app/img/logo-64x64.png | Bin 0 -> 832 bytes build/owncloud/rainloop-app/img/mail.png | Bin 0 -> 1518 bytes build/owncloud/rainloop-app/index.php | 41 +++++ build/owncloud/rainloop-app/js/admin.js | 13 ++ build/owncloud/rainloop-app/js/personal.js | 13 ++ build/owncloud/rainloop-app/js/rainloop.js | 76 ++++++++ .../rainloop-app/lib/RainLoopHelper.php | 62 +++++++ build/owncloud/rainloop-app/personal.php | 39 ++++ .../owncloud/rainloop-app/templates/admin.php | 23 +++ .../owncloud/rainloop-app/templates/empty.php | 1 + .../rainloop-app/templates/index-empty.php | 1 + .../owncloud/rainloop-app/templates/index.php | 3 + .../rainloop-app/templates/personal.php | 18 ++ dev/Storages/AbstractAjaxRemote.js | 4 +- .../v/0.0.0/app/libraries/RainLoop/Api.php | 14 +- .../libraries/RainLoop/Config/Application.php | 4 +- .../app/libraries/RainLoop/ServiceActions.php | 79 +++++--- rainloop/v/0.0.0/static/css/app.css | 18 +- rainloop/v/0.0.0/static/js/admin.js | 110 ++++++------ rainloop/v/0.0.0/static/js/admin.min.js | 8 +- rainloop/v/0.0.0/static/js/app.js | 170 +++++++++--------- rainloop/v/0.0.0/static/js/app.min.js | 12 +- 29 files changed, 724 insertions(+), 195 deletions(-) create mode 100644 build/owncloud/rainloop-app/INSTALL create mode 100644 build/owncloud/rainloop-app/admin.php create mode 100644 build/owncloud/rainloop-app/ajax/admin.php create mode 100644 build/owncloud/rainloop-app/ajax/personal.php create mode 100644 build/owncloud/rainloop-app/appinfo/app.php create mode 100644 build/owncloud/rainloop-app/appinfo/info.xml create mode 100644 build/owncloud/rainloop-app/img/logo-64x64.png create mode 100644 build/owncloud/rainloop-app/img/mail.png create mode 100644 build/owncloud/rainloop-app/index.php create mode 100644 build/owncloud/rainloop-app/js/admin.js create mode 100644 build/owncloud/rainloop-app/js/personal.js create mode 100644 build/owncloud/rainloop-app/js/rainloop.js create mode 100644 build/owncloud/rainloop-app/lib/RainLoopHelper.php create mode 100644 build/owncloud/rainloop-app/personal.php create mode 100644 build/owncloud/rainloop-app/templates/admin.php create mode 100644 build/owncloud/rainloop-app/templates/empty.php create mode 100644 build/owncloud/rainloop-app/templates/index-empty.php create mode 100644 build/owncloud/rainloop-app/templates/index.php create mode 100644 build/owncloud/rainloop-app/templates/personal.php diff --git a/Gruntfile.js b/Gruntfile.js index 3c6f7e5c1..733ab7f6b 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -10,7 +10,7 @@ module.exports = function (grunt) { cfg: { devVersion: "0.0.0", releasesPath: 'build/dist/releases', - releasesSrcPath: '', + releaseSrcPath: '', releaseFolder: 'rainloop', releaseZipFile: 'rainloop.zip' }, @@ -375,6 +375,17 @@ module.exports = function (grunt) { cwd: '<%= cfg.releasesPath %>/<%= cfg.releaseFolder %>/src/', src: ['**/*'] }] + }, + own: { + options: { + archive: '<%= cfg.releasesPath %>/<%= cfg.releaseFolder %>/<%= cfg.releaseZipFile %>', + mode: 'zip' + }, + files: [{ + expand: true, + cwd: '<%= cfg.releasesPath %>/<%= cfg.releaseFolder %>/owncloud/', + src: ['**/*'] + }] } }, @@ -450,15 +461,42 @@ module.exports = function (grunt) { packageJsonContent.replace(/"release":\s?"[\d]+",/, '"release": "' + (1 + parseInt(release, 10)) + '",')); grunt.config.set('cfg.releaseFolder', versionFull); - grunt.config.set('cfg.releasesSrcPath', dist); + grunt.config.set('cfg.releaseSrcPath', dist); grunt.config.set('cfg.releaseZipFile', 'rainloop-' + versionFull + '.zip'); }); + grunt.registerTask('rainloop-owncloud', 'RainLoop ownCloud App build task', function () { + + var + content = '', + version = grunt.config('pkg.version'), + release = grunt.config('pkg.release'), + releasesPath = grunt.config('cfg.releasesPath'), + devVersion = grunt.config('cfg.devVersion'), + versionFull = version + '.' + release, + dist = releasesPath + '/' + versionFull + '/owncloud/' + ; + + grunt.file.mkdir(dist); + + require('wrench').copyDirSyncRecursive('build/owncloud/rainloop-app', + dist, {'forceDelete': true}); + + content = grunt.file.read(dist + 'appinfo/info.xml'); + + grunt.file.write(dist + 'appinfo/info.xml', + content.replace('0.0.0', '' + version + '')); + + grunt.config.set('cfg.releaseFolder', versionFull); + grunt.config.set('cfg.releaseSrcPath', dist); + grunt.config.set('cfg.releaseZipFile', 'rainloop-owncloud-app-' + versionFull + '.zip'); + }); + grunt.registerTask('rainloop-clear', 'RainLoop Webmail clear task', function () { - var releasesSrcPath = grunt.config('cfg.releasesSrcPath'); - if ('' !== releasesSrcPath) + var releaseSrcPath = grunt.config('cfg.releaseSrcPath'); + if ('' !== releaseSrcPath) { - require('wrench').rmdirSyncRecursive(releasesSrcPath); + require('wrench').rmdirSyncRecursive(releaseSrcPath); } }); @@ -479,6 +517,7 @@ module.exports = function (grunt) { grunt.registerTask('default', ['less', 'concat', 'cssmin', 'jshint', 'rlmin']); grunt.registerTask('build', ['default', 'rainloop', 'compress:build', 'md5:build', 'rainloop-clear']); grunt.registerTask('fast', ['less', 'concat']); + grunt.registerTask('owncloud', ['rainloop-owncloud', 'compress:own', 'md5:build', 'rainloop-clear']); // aliases grunt.registerTask('u', ['uglify']); @@ -486,4 +525,6 @@ module.exports = function (grunt) { grunt.registerTask('b', ['build']); grunt.registerTask('f', ['fast']); grunt.registerTask('w', ['default', 'watch']); + grunt.registerTask('o', ['owncloud']); + grunt.registerTask('own', ['owncloud']); }; diff --git a/build/owncloud/rainloop-app/INSTALL b/build/owncloud/rainloop-app/INSTALL new file mode 100644 index 000000000..bb223e8d3 --- /dev/null +++ b/build/owncloud/rainloop-app/INSTALL @@ -0,0 +1,29 @@ +************************************************************************ +* +* ownCloud - RainLoop mail plugin +* +* @author RainLoop Team +* @copyright 2014 RainLoop Team +* +* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud +* +************************************************************************ + +INSTALL: +- Unpack the RainLoop Webmail application package in the apps directory of your OwnCloud instance + +CONFIGURATION: + +RainLoop: + 1) Open ../_default_/configs/application.ini + 2) Find: + +[labs] +allow_external_sso = On +external_sso_key = "super-secret-key" + +ownCloud: + 1) In the Apps > Enable 'RainLoop' plugin + 2) In the Settings > Admin > Enter "RainLoop Webmail URL" and "SSO key" + 3) In the Settings > Personal > Type your mail server email and password + diff --git a/build/owncloud/rainloop-app/admin.php b/build/owncloud/rainloop-app/admin.php new file mode 100644 index 000000000..d90c833be --- /dev/null +++ b/build/owncloud/rainloop-app/admin.php @@ -0,0 +1,19 @@ +assign('rainloop-url', OCP\Config::getAppValue('rainloop', 'rainloop-url', '')); +$oTemplate->assign('rainloop-sso-key', OCP\Config::getAppValue('rainloop', 'rainloop-sso-key', '')); +return $oTemplate->fetchPage(); diff --git a/build/owncloud/rainloop-app/ajax/admin.php b/build/owncloud/rainloop-app/ajax/admin.php new file mode 100644 index 000000000..ccb421a91 --- /dev/null +++ b/build/owncloud/rainloop-app/ajax/admin.php @@ -0,0 +1,33 @@ + 'Invalid Argument(s)', 'Url' => $sUrl, 'SsoKey' => $sSsoKey)); + return false; +} + +OCP\JSON::success(array('Message' => 'Saved successfully', 'Url' => $sUrl, 'SsoKey' => $sSsoKey)); +return true; diff --git a/build/owncloud/rainloop-app/ajax/personal.php b/build/owncloud/rainloop-app/ajax/personal.php new file mode 100644 index 000000000..f9b3a0b7a --- /dev/null +++ b/build/owncloud/rainloop-app/ajax/personal.php @@ -0,0 +1,45 @@ + 'Invalid argument(s)', 'Email' => $sEmail, 'Login' => $sLogin)); + return false; +} + +OCP\JSON::success(array('Message' => 'Saved successfully', 'Email' => $sEmail, 'Login' => $sLogin)); +return true; diff --git a/build/owncloud/rainloop-app/appinfo/app.php b/build/owncloud/rainloop-app/appinfo/app.php new file mode 100644 index 000000000..9e9785310 --- /dev/null +++ b/build/owncloud/rainloop-app/appinfo/app.php @@ -0,0 +1,23 @@ + 'rainloop_index', + 'order' => 10, + 'href' => OCP\Util::linkTo('rainloop', 'index.php'), + 'icon' => OCP\Util::imagePath('rainloop', 'mail.png'), + 'name' => 'RainLoop' +)); diff --git a/build/owncloud/rainloop-app/appinfo/info.xml b/build/owncloud/rainloop-app/appinfo/info.xml new file mode 100644 index 000000000..e4f04473f --- /dev/null +++ b/build/owncloud/rainloop-app/appinfo/info.xml @@ -0,0 +1,10 @@ + + + rainloop + RainLoop + RainLoop Webmail + 0.0.0 + CC BY-NC-SA 3.0 + RainLoop Team + 6.0 + \ No newline at end of file diff --git a/build/owncloud/rainloop-app/img/logo-64x64.png b/build/owncloud/rainloop-app/img/logo-64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..ce1dd1a886c906ec36cee1dec72b9df605886f02 GIT binary patch literal 832 zcmV-G1Hb%k7RCwC#n$brDK^(`2<+!Jah`6UC zB6^C5h=@4)4|jR5=a_ zzRF^}svNfv^ZdeBqWN>ez`6O3CP!Ob6K4KgljDGB{)*sTz z^!1_w(9GG-TyfDP!Xo{00A?<4KW=CfaL&!$~?mW93ud- z3_)ie1;GE|1Obpm2w~>A#vwlZ0OULT3;~cO2o&>Dvk;$t01|?#%xy-f#%wh&H3#uH z%$L{-A&Pnb^MGX;LLBpvWebE<%-aGXRr6^>@B+0UGRf&e7>ied9i0f84^6TZJ!A+9whO+(;!!F#YF;zg_o!^}%< zGkk06A@JD`#0GHz6bHf##J%YUURb+q4dR=rH)D8#QX6s=7zaZ2Kh67ZKWsPpMwF>h zmcl094*z1_Z=xoi4f_x)S#E};)g`u~9hP>B+z5nnM$H?8a7BP%`{qb22=eStDWm3x zg)jxNiZw*A)>t0*2B$?WvJ%!1$@}hbPqxO2d_LeA15oG_B85LARQOY3?wp_|o{0^U zHL<40a`3hPI3dTTW*ofXI!ef~!-ywEDQATr105Wd)|viX?ieA*mL>=98jTQg>=7rG z!(@x>@8onp!CAW{&f2af2c=}kUg0{JbIi%f$;rvd$*HLN6<`1!uF_d9==`$)0000< KMNUMnLSTX$7j)+U literal 0 HcmV?d00001 diff --git a/build/owncloud/rainloop-app/img/mail.png b/build/owncloud/rainloop-app/img/mail.png new file mode 100644 index 0000000000000000000000000000000000000000..21076eed70fcfaf735b09c0c5fbadf342cb72e4d GIT binary patch literal 1518 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$jZRL%n;xc;tCZ1|NlRb90j8xFakp$z3fdgFrP4#1o;I6Gr~v)48h;oRe?!> zv%n*=n1O-sFbFdq&tH)O6qG7)jVKAuPb(=;EJ|evNX*PD(erZ+Q7ALkGu1ORbpPyR z4h%+DPZ!6K2=}*ByoC-c@Hk)oEk8?2;DLOnZ~5GeiG?j+F3mi)^HhHo~t_ZV?VAV#ZR~*I*;aq&}-?7w|)(Yk+_k0A?b}%kr zX>`A-*TSiEV!Ecs1Vg?K!4MAyB^KF<4e3ps8V7_A%4Hw0J!omtVBJ(+5}EB?z@IVG zKsT3TUvKV|qQ!Xy%pVTTzQdOAc=wHe;vTmpVnqY=qfB+Ujy0TE^!>mO+f!V}W;~Lg zvQlskYjVNey`3f(Ph`nGtP|IAx|=-f5`*Z(+WrL$=aiTDI55fmHdA6~+{anyuws2O zkHDMN4}L9Z`E6unuhF@Wqd(W@Yx*2L29@879j5bnd=HdtXs%OdD7cc}!r3rYgxTa^ z-X*u)+uc~#6l!Koc(uAG6G$D=oAZ)&PeYK`Po|ibYfKs;Ywm)wqo=E%%Q~loCIGoJ Bx~TvF literal 0 HcmV?d00001 diff --git a/build/owncloud/rainloop-app/index.php b/build/owncloud/rainloop-app/index.php new file mode 100644 index 000000000..b6c59378c --- /dev/null +++ b/build/owncloud/rainloop-app/index.php @@ -0,0 +1,41 @@ +assign('rainloop-url', $sResultUrl); +} + +$oTemplate->printpage(); diff --git a/build/owncloud/rainloop-app/js/admin.js b/build/owncloud/rainloop-app/js/admin.js new file mode 100644 index 000000000..48865ff00 --- /dev/null +++ b/build/owncloud/rainloop-app/js/admin.js @@ -0,0 +1,13 @@ + +/** + * ownCloud - RainLoop mail plugin + * + * @author RainLoop Team + * @copyright 2014 RainLoop Team + * + * https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud + */ + +$(function() { + RainLoopFormHelper('#mail-rainloop-admin-form', 'admin.php'); +}); diff --git a/build/owncloud/rainloop-app/js/personal.js b/build/owncloud/rainloop-app/js/personal.js new file mode 100644 index 000000000..f1f988bc1 --- /dev/null +++ b/build/owncloud/rainloop-app/js/personal.js @@ -0,0 +1,13 @@ + +/** + * ownCloud - RainLoop mail plugin + * + * @author RainLoop Team + * @copyright 2014 RainLoop Team + * + * https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud + */ + +$(function() { + RainLoopFormHelper('#mail-rainloop-personal-form', 'personal.php'); +}); diff --git a/build/owncloud/rainloop-app/js/rainloop.js b/build/owncloud/rainloop-app/js/rainloop.js new file mode 100644 index 000000000..e48404759 --- /dev/null +++ b/build/owncloud/rainloop-app/js/rainloop.js @@ -0,0 +1,76 @@ + +function RainLoopFormHelper(sID, sAjaxFile, fCallback) +{ + try + { + var + oForm = $(sID), + oSubmit = $('#rainloop-save-button', oForm), + sSubmitValue = oSubmit.val(), + oDesc = oForm.find('.rainloop-result-desc') + ; + + oSubmit.click(function (oEvent) { + + var oDefAjax = null; + + oEvent.preventDefault(); + + oForm + .addClass('rainloop-ajax') + .removeClass('rainloop-error') + .removeClass('rainloop-success') + ; + + oDesc.text(''); + oSubmit.val('...'); + + oDefAjax = $.ajax({ + 'type': 'POST', + 'async': true, + 'url': OC.filePath('rainloop', 'ajax', sAjaxFile), + 'data': oForm.serialize(), + 'dataType': 'json', + 'global': true + }); + + oDefAjax.always(function (oData) { + + var bResult = false; + + oForm.removeClass('rainloop-ajax'); + oSubmit.val(sSubmitValue); + + if (oData) + { + bResult = 'success' === oData['status']; + if (oData['Message']) + { + oDesc.text(oData['Message']); + } + } + + if (bResult) + { + oForm.addClass('rainloop-success'); + } + else + { + oForm.addClass('rainloop-error'); + if ('' === oDesc.text()) + { + oDesc.text('Error'); + } + } + + if (fCallback) + { + fCallback(bResult, oData); + } + }); + + return false; + }); + } + catch(e) {} +} diff --git a/build/owncloud/rainloop-app/lib/RainLoopHelper.php b/build/owncloud/rainloop-app/lib/RainLoopHelper.php new file mode 100644 index 000000000..798aaad54 --- /dev/null +++ b/build/owncloud/rainloop-app/lib/RainLoopHelper.php @@ -0,0 +1,62 @@ + $sUrl.'?ExternalSso', + CURLOPT_HEADER => false, + CURLOPT_FAILONERROR => true, + CURLOPT_SSL_VERIFYPEER => false, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => true, + CURLOPT_USERAGENT => 'RainLoop SSO User Agent (ownCloud)', + CURLOPT_POSTFIELDS => http_build_query(array( + 'SsoKey' => $sSsoKey, + 'Email' => $sEmail, + 'Password' => $sPassword, + 'Login' => $sLogin + ), '', '&'), + CURLOPT_TIMEOUT => 5 + )); + + $mResult = curl_exec($oCurl); + if (is_resource($oCurl)) + { + curl_close($oCurl); + } + + return is_string($mResult) ? $mResult : ''; + } + + public static function encodePassword($sPassword, $sSalt) + { + if (function_exists('mcrypt_encrypt') && function_exists('mcrypt_create_iv') && function_exists('mcrypt_get_iv_size') && + defined('MCRYPT_RIJNDAEL_256') && defined('MCRYPT_MODE_ECB') && defined('MCRYPT_RAND')) + { + return @trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($sSalt), $sPassword, + MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)))); + } + + return @trim(base64_encode($sPassword)); + } + + public static function decodePassword($sPassword, $sSalt) + { + if (function_exists('mcrypt_encrypt') && function_exists('mcrypt_create_iv') && function_exists('mcrypt_get_iv_size') && + defined('MCRYPT_RIJNDAEL_256') && defined('MCRYPT_MODE_ECB') && defined('MCRYPT_RAND')) + { + return @mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($sSalt), base64_decode(trim($sPassword)), + MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)); + } + + return @base64_decode(trim($sPassword)); + } +} diff --git a/build/owncloud/rainloop-app/personal.php b/build/owncloud/rainloop-app/personal.php new file mode 100644 index 000000000..9aa1a9071 --- /dev/null +++ b/build/owncloud/rainloop-app/personal.php @@ -0,0 +1,39 @@ +assign('rainloop-email', $sEmail); + $oTemplate->assign('rainloop-login', OCP\Config::getUserValue($sUser, 'rainloop', 'rainloop-login', '')); + + $sPass = OCP\Config::getUserValue($sUser, 'rainloop', 'rainloop-password', ''); + $oTemplate->assign('rainloop-password', 0 === strlen($sPass) && 0 === strlen($sEmail) ? '' : '******'); +} + +return $oTemplate->fetchPage(); diff --git a/build/owncloud/rainloop-app/templates/admin.php b/build/owncloud/rainloop-app/templates/admin.php new file mode 100644 index 000000000..f7d05d171 --- /dev/null +++ b/build/owncloud/rainloop-app/templates/admin.php @@ -0,0 +1,23 @@ +
+ + + +
+

t('RainLoop Webmail')); ?>

+
+

+ t('RainLoop Webmail URL')); ?>: +
+ +
+
+ t('SSO key')); ?>: +
+ +
+
+ +    +

+
+
\ No newline at end of file diff --git a/build/owncloud/rainloop-app/templates/empty.php b/build/owncloud/rainloop-app/templates/empty.php new file mode 100644 index 000000000..fa0c45f25 --- /dev/null +++ b/build/owncloud/rainloop-app/templates/empty.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/build/owncloud/rainloop-app/templates/index-empty.php b/build/owncloud/rainloop-app/templates/index-empty.php new file mode 100644 index 000000000..1ec6b8a65 --- /dev/null +++ b/build/owncloud/rainloop-app/templates/index-empty.php @@ -0,0 +1 @@ +EMPTY \ No newline at end of file diff --git a/build/owncloud/rainloop-app/templates/index.php b/build/owncloud/rainloop-app/templates/index.php new file mode 100644 index 000000000..754c7f87b --- /dev/null +++ b/build/owncloud/rainloop-app/templates/index.php @@ -0,0 +1,3 @@ +
+ +
\ No newline at end of file diff --git a/build/owncloud/rainloop-app/templates/personal.php b/build/owncloud/rainloop-app/templates/personal.php new file mode 100644 index 000000000..880e00d5e --- /dev/null +++ b/build/owncloud/rainloop-app/templates/personal.php @@ -0,0 +1,18 @@ +
+ + + +
+

t('RainLoop Webmail')); ?>

+

+ + + + + +    +

+
+
\ No newline at end of file diff --git a/dev/Storages/AbstractAjaxRemote.js b/dev/Storages/AbstractAjaxRemote.js index 2fed22c21..2d82264d6 100644 --- a/dev/Storages/AbstractAjaxRemote.js +++ b/dev/Storages/AbstractAjaxRemote.js @@ -37,7 +37,7 @@ AbstractAjaxRemoteStorage.prototype.defaultResponse = function (fCallback, sRequ { Globals.iAjaxErrorCount++; } - + if (oData && Enums.Notification.InvalidToken === oData.ErrorCode) { Globals.iTokenErrorCount++; @@ -63,7 +63,7 @@ AbstractAjaxRemoteStorage.prototype.defaultResponse = function (fCallback, sRequ Globals.iAjaxErrorCount = 0; Globals.iTokenErrorCount = 0; } - + if (fCallback) { Plugins.runHook('ajax-default-response', [sRequestAction, Enums.StorageResultType.Success === sType ? oData : null, sType, bCached, oRequestParameters]); diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php index fbb4072d0..1cf75b1df 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Api.php @@ -21,7 +21,7 @@ class Api { $oActions = \RainLoop\Actions::NewInstance(); } - + return $oActions; } @@ -43,7 +43,7 @@ class Api { return true; } - + if (!\class_exists('MailSo\Version')) { return false; @@ -63,17 +63,19 @@ class Api * @param string $sEmail * @param string $sPassword * @param string $sLogin = '' - * - * @return string + * @param bool $bUseTimeout = true + * + * @return string */ - public static function GetUserSsoHash($sEmail, $sPassword, $sLogin = '') + public static function GetUserSsoHash($sEmail, $sPassword, $sLogin = '', $bUseTimeout = true) { $sSsoHash = \sha1(\rand(10000, 99999).$sEmail.$sPassword.$sLogin.\microtime(true)); return self::Actions()->Cacher()->Set(self::Actions()->BuildSsoCacherKey($sSsoHash), \RainLoop\Utils::EncodeKeyValues(array( 'Email' => $sEmail, 'Password' => $sPassword, - 'Login' => $sLogin + 'Login' => $sLogin, + 'Time' => $bUseTimeout ? \time() : 0 ))) ? $sSsoHash : ''; } diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php index 3409590be..529e93cfc 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/Config/Application.php @@ -140,7 +140,7 @@ Values: 'logs' => array( 'enable' => array(false, 'Enable logging'), - + 'write_on_error_only' => array(false, 'Logs entire request only if error occured'), 'write_on_timeout_only' => array(0, 'Logs entire request only if request timeout (in seconds) occured.'), @@ -245,6 +245,8 @@ Enables caching in the system'), 'custom_login_link' => array(''), 'custom_logout_link' => array(''), 'allow_external_login' => array(false), + 'allow_external_sso' => array(false), + 'external_sso_key' => array(''), 'fast_cache_memcache_host' => array('127.0.0.1'), 'fast_cache_memcache_port' => array(11211), 'fast_cache_memcache_expire' => array(43200), diff --git a/rainloop/v/0.0.0/app/libraries/RainLoop/ServiceActions.php b/rainloop/v/0.0.0/app/libraries/RainLoop/ServiceActions.php index 24024744f..2805de5b1 100644 --- a/rainloop/v/0.0.0/app/libraries/RainLoop/ServiceActions.php +++ b/rainloop/v/0.0.0/app/libraries/RainLoop/ServiceActions.php @@ -256,7 +256,7 @@ class ServiceActions /** * @param string $sAction - * + * * @return string */ private function privateUpload($sAction) @@ -321,7 +321,7 @@ class ServiceActions { return $this->privateUpload('UploadContacts'); } - + /** * @return string */ @@ -329,7 +329,7 @@ class ServiceActions { return $this->privateUpload('UploadBackground'); } - + /** * @return string */ @@ -388,7 +388,7 @@ class ServiceActions { $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR, 'RAW'); } - + return $sResult; } @@ -399,7 +399,7 @@ class ServiceActions { $sResult = ''; @\header('Content-Type: application/javascript; charset=utf-8'); - + if (!empty($this->aPaths[2])) { $sLanguage = $this->oActions->ValidateLanguage($this->aPaths[2]); @@ -519,7 +519,7 @@ class ServiceActions public function ServiceCss() { $sResult = ''; - + $bAdmin = !empty($this->aPaths[2]) && 'Admin' === $this->aPaths[2]; $bJson = !empty($this->aPaths[7]) && 'Json' === $this->aPaths[7]; @@ -537,13 +537,13 @@ class ServiceActions { $sTheme = $this->oActions->ValidateTheme($this->aPaths[4]); $sRealTheme = $sTheme; - + $bCustomTheme = '@custom' === \substr($sTheme, -7); if ($bCustomTheme) { $sRealTheme = \substr($sTheme, 0, -7); } - + $bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true); if ($bCacheEnabled) { @@ -646,7 +646,7 @@ class ServiceActions { return $this->localAppData(false); } - + /** * @return string */ @@ -670,7 +670,7 @@ class ServiceActions { return $this->localError($this->oActions->StaticI18N('STATIC/NO_COOKIE_TITLE'), $this->oActions->StaticI18N('STATIC/NO_COOKIE_DESC')); } - + /** * @return string */ @@ -706,7 +706,7 @@ class ServiceActions $this->oActions->Location('./'); return ''; } - + /** * @return string */ @@ -742,14 +742,15 @@ class ServiceActions { $mData = null; $sSsoKey = $this->oActions->BuildSsoCacherKey($sSsoHash); - + $sSsoSubData = $this->Cacher()->Get($sSsoKey); if (!empty($sSsoSubData)) { $mData = \RainLoop\Utils::DecodeKeyValues($sSsoSubData); $this->Cacher()->Delete($sSsoKey); - if (\is_array($mData) && !empty($mData['Email']) && isset($mData['Password'])) + if (\is_array($mData) && !empty($mData['Email']) && isset($mData['Password'], $mData['Time']) && + (0 === $mData['Time'] || \time() - 10 < $mData['Time'])) { $sEmail = \trim($mData['Email']); $sPassword = $mData['Password']; @@ -812,11 +813,11 @@ class ServiceActions { $oException = null; $oAccount = null; - + if ($this->oActions->Config()->Get('labs', 'allow_external_login', false)) { - $sEmail = trim($this->oHttp->GetRequest('Email', '')); - $sLogin = trim($this->oHttp->GetRequest('Login', '')); + $sEmail = \trim($this->oHttp->GetRequest('Email', '')); + $sLogin = \trim($this->oHttp->GetRequest('Login', '')); $sPassword = $this->oHttp->GetRequest('Password', ''); try @@ -835,9 +836,9 @@ class ServiceActions switch (\strtolower($this->oHttp->GetRequest('Output', 'Redirect'))) { case 'json': - + @\header('Content-Type: application/json; charset=utf-8'); - + $aResult = array( 'Action' => 'ExternalLogin', 'Result' => $oAccount instanceof \RainLoop\Account ? true : false, @@ -857,7 +858,7 @@ class ServiceActions } return \MailSo\Base\Utils::Php2js($aResult); - + case 'redirect': default: $this->oActions->Location('./'); @@ -866,7 +867,41 @@ class ServiceActions return ''; } - + + /** + * @return string + */ + public function ServiceExternalSso() + { + $sKey = $this->oActions->Config()->Get('labs', 'external_sso_key', ''); + if ($this->oActions->Config()->Get('labs', 'allow_external_sso', false) && + !empty($sKey) && $sKey === \trim($this->oHttp->GetRequest('SsoKey', ''))) + { + $sEmail = \trim($this->oHttp->GetRequest('Email', '')); + $sLogin = \trim($this->oHttp->GetRequest('Login', '')); + $sPassword = $this->oHttp->GetRequest('Password', ''); + + \RainLoop\Api::Handle(); + $sResult = \RainLoop\Api::GetUserSsoHash($sEmail, $sPassword, $sLogin); + + switch (\strtolower($this->oHttp->GetRequest('Output', 'Plain'))) + { + case 'plain': + @\header('Content-Type: text/plain'); + return $sResult; + + case 'json': + @\header('Content-Type: application/json; charset=utf-8'); + return \MailSo\Base\Utils::Php2js(array( + 'Action' => 'ExternalSso', + 'Result' => $sResult + )); + } + } + + return ''; + } + /** * @return string */ @@ -941,7 +976,7 @@ class ServiceActions $sAuthAccountHash = $this->oActions->GetSpecAuthToken(); } } - + $this->oActions->SetSpecAuthToken($sAuthAccountHash); } @@ -962,7 +997,7 @@ class ServiceActions { $sHtml = \RainLoop\Utils::CompileTemplates(APP_VERSION_ROOT_PATH.'app/templates/Views', $this->oActions). $this->oActions->Plugins()->CompileTemplate($bAdmin); - + return ($bWrapByScriptTag ? '