Redesign Nextcloud integration with better security and SSO #96

This commit is contained in:
the-djmaze 2022-10-10 22:06:43 +02:00
parent a6d5f6ad91
commit 32059330dd
7 changed files with 162 additions and 662 deletions

View file

@ -16,8 +16,8 @@ class Application extends App {
parent::__construct('snappymail', $urlParams);
$container = $this->getContainer();
$server = $container->getServer();
$config = $server->getConfig();
// $server = $container->getServer();
// $config = $server->getConfig();
/**
* Controllers
@ -26,10 +26,7 @@ class Application extends App {
'PageController', function($c) {
return new PageController(
$c->query('AppName'),
$c->query('Request'),
$c->getServer()->getAppManager(),
$c->query('ServerContainer')->getConfig(),
$c->getServer()->getSession()
$c->query('Request')
);
}
);
@ -51,12 +48,7 @@ class Application extends App {
*/
$container->registerService(
'SnappyMailHelper', function($c) {
return new SnappyMailHelper(
$c->getServer()->getConfig(),
$c->getServer()->getUserSession(),
$c->getServer()->getAppManager(),
$c->getServer()->getSession()
);
return new SnappyMailHelper();
}
);

View file

@ -67,10 +67,10 @@ class AjaxController extends Controller {
$sPass = $_POST['snappymail-password'];
if ('******' !== $sPass && '' !== $sPass) {
include_once $this->appManager->getAppPath('snappymail').'/lib/Util/SnappyMailHelper.php';
require_once $this->appManager->getAppPath('snappymail').'/lib/Util/SnappyMailHelper.php';
$this->config->setUserValue($sUser, 'snappymail', 'snappymail-password',
SnappyMailHelper::encodePassword($sPass, md5($sPostEmail)));
SnappyMailHelper::encodePassword($sPass, \md5($sPostEmail)));
}
$sEmail = $this->config->getUserValue($sUser, 'snappymail', 'snappymail-email', '');

View file

@ -4,42 +4,26 @@ namespace OCA\SnappyMail\Controller;
use OCA\SnappyMail\Util\SnappyMailHelper;
use OCP\App\IAppManager;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IConfig;
use OCP\IRequest;
use OCP\ISession;
class PageController extends Controller {
private $userId;
private $config;
private $appManager;
private $appPath;
private $session;
public function __construct($AppName, IRequest $request, IAppManager $appManager, IConfig $config, ISession $session) {
parent::__construct($AppName, $request);
$this->appPath = $appManager->getAppPath('snappymail');
$this->config = $config;
$this->appManager = $appManager;
$this->session = $session;
}
class PageController extends Controller
{
/**
* @NoAdminRequired
* @NoCSRFRequired
*/
public function index() {
public function index()
{
\OC::$server->getNavigationManager()->setActiveEntry('snappymail');
\OCP\Util::addStyle('snappymail', 'style');
$sUrl = SnappyMailHelper::normalizeUrl(SnappyMailHelper::getAppUrl());
$session = \OC::$server->getSession();
$params = [
'snappymail-iframe-url' => SnappyMailHelper::normalizeUrl($sUrl).'?OwnCloudAuth'
'snappymail-iframe-url' => SnappyMailHelper::normalizeUrl(SnappyMailHelper::getAppUrl())
. (empty($session['snappymail-sso-hash']) ? '' : '?sso&hash=' . $session['snappymail-sso-hash'])
];
$response = new TemplateResponse('snappymail', 'index', $params);
@ -55,56 +39,18 @@ class PageController extends Controller {
* @NoAdminRequired
* @NoCSRFRequired
*/
public function appGet() {
$this->app();
public function appGet()
{
SnappyMailHelper::startApp();
}
/**
* @NoAdminRequired
* @NoCSRFRequired
*/
public function appPost() {
$this->app();
public function appPost()
{
SnappyMailHelper::startApp();
}
public function app() {
SnappyMailHelper::regSnappyMailDataFunction();
if (isset($_GET['OwnCloudAuth'])) {
$sEmail = '';
$sEncodedPassword = '';
$sUser = \OC::$server->getUserSession()->getUser()->getUID();
if ($this->config->getAppValue('snappymail', 'snappymail-autologin', false)) {
$sEmail = $sUser;
$sPasswordSalt = $sUser;
$sEncodedPassword = $this->session['snappymail-autologin-password'];
} else if ($this->config->getAppValue('snappymail', 'snappymail-autologin-with-email', false)) {
$sEmail = $this->config->getUserValue($sUser, 'settings', 'email', '');
$sPasswordSalt = $sUser;
$sEncodedPassword = $this->session['snappymail-autologin-password'];
}
// If the user has set credentials for SnappyMail in their personal
// settings, override everything before and use those instead.
$sIndividualEmail = $this->config->getUserValue($sUser, 'snappymail', 'snappymail-email', '');
if ($sIndividualEmail) {
$sEmail = $sIndividualEmail;
$sPasswordSalt = $sEmail;
$sEncodedPassword = $this->config->getUserValue($sUser, 'snappymail', 'snappymail-password', '');
}
$sDecodedPassword = SnappyMailHelper::decodePassword($sEncodedPassword, md5($sPasswordSalt));
$_ENV['___snappymail_owncloud_email'] = $sEmail;
$_ENV['___snappymail_owncloud_password'] = $sDecodedPassword;
}
include $this->appPath . '/app/index.php';
}
}

View file

@ -2,33 +2,59 @@
namespace OCA\SnappyMail\Util;
use OCP\App\IAppManager;
use OCP\IConfig;
use OCP\ISession;
use OCP\IUserSession;
class SnappyMailHelper
{
class SnappyMailHelper {
public function registerHooks()
{
$config = \OC::$server->getConfig();
$session = \OC::$server->getSession();
$userSession = \OC::$server->getUserSession();
$userSession->listen('\OC\User', 'postLogin', function($user, $loginName, $password, $isTokenLogin) {
$sEmail = '';
// If the user has set credentials for SnappyMail in their personal
// settings, override everything before and use those instead.
$sIndividualEmail = $config->getUserValue($user->getUID(), 'snappymail', 'snappymail-email', '');
if ($sIndividualEmail) {
$sEmail = $sIndividualEmail;
$password = SnappyMailHelper::decodePassword(
$this->config->getUserValue($sUser, 'snappymail', 'snappymail-password', ''),
\md5($sEmail)
);
}
// Only store the user's password in the current session if they have
// enabled auto-login using Nextcloud username or email address.
else if ($config->getAppValue('snappymail', 'snappymail-autologin', false)) {
$sEmail = $user->getUID();
} else if ($config->getAppValue('snappymail', 'snappymail-autologin-with-email', false)) {
$sEmail = $config->getUserValue($user->getUID(), 'settings', 'email', '');
}
if ($sEmail) {
static::startApp(true);
$session['snappymail-sso-hash'] = \RainLoop\Api::CreateUserSsoHash($sEmail, $password/*, array $aAdditionalOptions = array(), bool $bUseTimeout = true*/);
}
});
private $appManager;
private $config;
private $session;
private $userSession;
public function __construct(IConfig $config, IUserSession $userSession, IAppManager $appManager, ISession $session) {
$this->appManager = $appManager;
$this->config = $config;
$this->userSession = $userSession;
$this->session = $session;
$userSession->listen('\OC\User', 'logout', function($user) {
$session['snappymail-sso-hash'] = '';
static::startApp(true);
\RainLoop\Api::LogoutCurrentLogginedUser();
});
}
public function registerHooks() {
$this->userSession->listen('\OC\User', 'postLogin', function($user, $loginName, $password, $isTokenLogin) {
$this->login($user, $loginName, $password, $isTokenLogin, $this->config, $this->session);
});
$this->userSession->listen('\OC\User', 'logout', function() {
$this->logout($this->appManager, $this->config, $this->session);
});
public static function startApp(bool $api = false)
{
if (!\class_exists('RainLoop\\Api')) {
if ($api) {
$_ENV['SNAPPYMAIL_INCLUDE_AS_API'] = true;
}
$_ENV['SNAPPYMAIL_NEXTCLOUD'] = true;
$sData = \rtrim(\trim(\OC::$server->getSystemConfig()->getValue('datadirectory', '')), '\\/').'/';
if (\is_dir($sData)) {
\define('APP_DATA_FOLDER_PATH', $sData);
}
require_once \OC::$server->getAppManager()->getAppPath('snappymail') . '/app/index.php';
}
}
/**
@ -37,44 +63,13 @@ class SnappyMailHelper {
public static function getAppUrl()
{
$sRequestUri = \OC::$server->getURLGenerator()->linkToRoute('snappymail.page.appGet');
if ($sRequestUri)
{
if ($sRequestUri) {
return $sRequestUri;
}
$sRequestUri = empty($_SERVER['REQUEST_URI']) ? '': trim($_SERVER['REQUEST_URI']);
$sRequestUri = preg_replace('/index.php\/.+$/', 'index.php/', $sRequestUri);
$sRequestUri = empty($_SERVER['REQUEST_URI']) ? '': \trim($_SERVER['REQUEST_URI']);
$sRequestUri = \preg_replace('/index.php\/.+$/', 'index.php/', $sRequestUri);
$sRequestUri = $sRequestUri.'apps/snappymail/app/';
return '/'.ltrim($sRequestUri, '/\\');
}
/**
* @param string $sPath
* @param string $sEmail
* @param string $sPassword
*
* @return string
*/
public static function getSsoHash($sPath, $sEmail, $sPassword)
{
$SsoHash = '';
$sPath = rtrim(trim($sPath), '\\/').'/index.php';
if (file_exists($sPath))
{
self::regSnappyMailDataFunction();
$_ENV['SNAPPYMAIL_INCLUDE_AS_API'] = true;
include $sPath;
if (class_exists('\\RainLoop\\Api'))
{
$SsoHash = \RainLoop\Api::GetUserSsoHash($sEmail, $sPassword);
}
}
return $SsoHash;
return '/'.\ltrim($sRequestUri, '/\\');
}
/**
@ -84,83 +79,14 @@ class SnappyMailHelper {
*/
public static function normalizeUrl($sUrl)
{
$sUrl = rtrim(trim($sUrl), '/\\');
if ('.php' !== strtolower(substr($sUrl, -4)))
{
$sUrl = \rtrim(\trim($sUrl), '/\\');
if ('.php' !== \strtolower(\substr($sUrl, -4))) {
$sUrl .= '/';
}
return $sUrl;
}
/**
* @return boolean
*/
public static function mcryptSupported()
{
return function_exists('mcrypt_encrypt') &&
function_exists('mcrypt_decrypt') &&
defined('MCRYPT_RIJNDAEL_256') &&
defined('MCRYPT_MODE_ECB');
}
/**
* @return string
*/
public static function openSslSupportedMethod()
{
$method = 'AES-256-CBC';
return function_exists('openssl_encrypt') &&
function_exists('openssl_decrypt') &&
function_exists('openssl_random_pseudo_bytes') &&
function_exists('openssl_cipher_iv_length') &&
function_exists('openssl_get_cipher_methods') &&
defined('OPENSSL_RAW_DATA') && defined('OPENSSL_ZERO_PADDING') &&
in_array($method, openssl_get_cipher_methods()) ? $method : '';
}
/**
* @param string $sMethod
* @param string $sPassword
* @param string $sSalt
*
* @return string
*/
public static function encodePasswordSsl($sMethod, $sPassword, $sSalt)
{
$sData = base64_encode($sPassword);
$iv = @openssl_random_pseudo_bytes(openssl_cipher_iv_length($sMethod));
$r = @openssl_encrypt($sData, $sMethod, md5($sSalt), OPENSSL_RAW_DATA, $iv);
return @base64_encode(base64_encode($r).'|'.base64_encode($iv));
}
/**
* @param string $sMethod
* @param string $sPassword
* @param string $sSalt
*
* @return string
*/
public static function decodePasswordSsl($sMethod, $sPassword, $sSalt)
{
$sLine = base64_decode(trim($sPassword));
$aParts = explode('|', $sLine, 2);
if (is_array($aParts) && !empty($aParts[0]) && !empty($aParts[1])) {
$sData = @base64_decode($aParts[0]);
$iv = @base64_decode($aParts[1]);
return @base64_decode(trim(
@openssl_decrypt($sData, $sMethod, md5($sSalt), OPENSSL_RAW_DATA, $iv)
));
}
return '';
}
/**
* @param string $sPassword
* @param string $sSalt
@ -169,19 +95,8 @@ class SnappyMailHelper {
*/
public static function encodePassword($sPassword, $sSalt)
{
$method = self::openSslSupportedMethod();
if ($method)
{
return self::encodePasswordSsl($method, $sPassword, $sSalt);
}
else if (self::mcryptSupported())
{
return @trim(base64_encode(
@mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($sSalt), base64_encode($sPassword), MCRYPT_MODE_ECB)
));
}
return @trim(base64_encode($sPassword));
static::startApp(true);
return \SnappyMail\Crypt::EncryptUrlSafe($sPassword, $sSalt);
}
/**
@ -192,150 +107,7 @@ class SnappyMailHelper {
*/
public static function decodePassword($sPassword, $sSalt)
{
$method = self::openSslSupportedMethod();
if ($method)
{
return self::decodePasswordSsl($method, $sPassword, $sSalt);
}
else if (self::mcryptSupported())
{
return @base64_decode(trim(
@mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($sSalt), base64_decode(trim($sPassword)), MCRYPT_MODE_ECB)
));
}
return @base64_decode(trim($sPassword));
static::startApp(true);
return \SnappyMail\Crypt::DecryptUrlSafe($sPassword, $sSalt);
}
/**
* @param array $aParams
* @return boolean
* @UseSession
*/
public static function login($user, $loginName, $password, $isTokenLogin, $config, &$session)
{
$sUser = $user->getUID();
$sEmail = $sUser;
$sPassword = $password;
$sEncodedPassword = self::encodePassword($sPassword, md5($sEmail));
// Only store the user's password in the current session if they have
// enabled auto-login using Nextcloud username or email address.
if ($config->getAppValue('snappymail', 'snappymail-autologin') || $config->getAppValue('snappymail', 'snappymail-autologin-with-email')) {
$session['snappymail-autologin-password'] = $sEncodedPassword;
}
}
/**
* @UseSession
*/
public static function logout($appManager, $config, &$session)
{
$session['snappymail-autologin-password'] = '';
$sApiPath = $appManager->getAppPath('snappymail') . '/app/index.php';
self::regSnappyMailDataFunction();
$_ENV['SNAPPYMAIL_INCLUDE_AS_API'] = true;
include $sApiPath;
\RainLoop\Api::LogoutCurrentLogginedUser();
return true;
}
public static function regSnappyMailDataFunction()
{
if (!@function_exists('__get_custom_data_full_path'))
{
$_ENV['SNAPPYMAIL_NEXTCLOUD'] = true;
function __get_custom_data_full_path()
{
$sData = rtrim(trim(OC::$server->getSystemConfig()->getValue('datadirectory', '')), '\\/').'/';
return @is_dir($sData) ? $sData.'snappymail-storage' : '';
}
}
}
public static function mimeContentType($filename) {
$mime_types = array(
'woff' => 'application/font-woff',
'txt' => 'text/plain',
'htm' => 'text/html',
'html' => 'text/html',
'php' => 'text/html',
'css' => 'text/css',
'js' => 'application/javascript',
'json' => 'application/json',
'xml' => 'application/xml',
'swf' => 'application/x-shockwave-flash',
'flv' => 'video/x-flv',
// images
'png' => 'image/png',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'gif' => 'image/gif',
'bmp' => 'image/bmp',
'ico' => 'image/vnd.microsoft.icon',
'tiff' => 'image/tiff',
'tif' => 'image/tiff',
'svg' => 'image/svg+xml',
'svgz' => 'image/svg+xml',
// archives
'zip' => 'application/zip',
'rar' => 'application/x-rar-compressed',
'exe' => 'application/x-msdownload',
'msi' => 'application/x-msdownload',
'cab' => 'application/vnd.ms-cab-compressed',
// audio/video
'mp3' => 'audio/mpeg',
'qt' => 'video/quicktime',
'mov' => 'video/quicktime',
// adobe
'pdf' => 'application/pdf',
'psd' => 'image/vnd.adobe.photoshop',
'ai' => 'application/postscript',
'eps' => 'application/postscript',
'ps' => 'application/postscript',
// ms office
'doc' => 'application/msword',
'rtf' => 'application/rtf',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
// open office
'odt' => 'application/vnd.oasis.opendocument.text',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
);
if (0 < strpos($filename, '.'))
{
$ext = strtolower(array_pop(explode('.',$filename)));
if (array_key_exists($ext, $mime_types))
{
return $mime_types[$ext];
}
else if (function_exists('finfo_open'))
{
$finfo = finfo_open(FILEINFO_MIME);
$mimetype = finfo_file($finfo, $filename);
finfo_close($finfo);
return $mimetype;
}
}
return 'application/octet-stream';
}
}