Added Allow/Disallow multiple identities

This commit is contained in:
RainLoop Team 2015-05-18 00:38:20 +04:00
parent 28d93f70ae
commit 2f482a6288
49 changed files with 32740 additions and 32243 deletions

View file

@ -16,7 +16,7 @@ It's not recommended to use in production environment.
## License ## License
RainLoop Webmail (**Community edition**) is released under **RainLoop Webmail (Community edition)** is released under
**GNU AFFERO GENERAL PUBLIC LICENSE Version 3 (AGPL)**. **GNU AFFERO GENERAL PUBLIC LICENSE Version 3 (AGPL)**.
http://www.gnu.org/licenses/agpl-3.0.html http://www.gnu.org/licenses/agpl-3.0.html

View file

@ -225,7 +225,6 @@
{ {
var var
kn = require('Knoin/Knoin'), kn = require('Knoin/Knoin'),
sStartupUrl = Utils.pString(Settings.settingsGet('StartupUrl')),
sCustomLogoutLink = Utils.pString(Settings.settingsGet('CustomLogoutLink')), sCustomLogoutLink = Utils.pString(Settings.settingsGet('CustomLogoutLink')),
bInIframe = !!Settings.settingsGet('InIframe') bInIframe = !!Settings.settingsGet('InIframe')
; ;
@ -235,7 +234,6 @@
if (bLogout) if (bLogout)
{ {
sStartupUrl = '';
this.clearClientSideToken(); this.clearClientSideToken();
} }
@ -244,11 +242,6 @@
window.close(); window.close();
} }
if (bAdmin)
{
sStartupUrl = '';
}
sCustomLogoutLink = sCustomLogoutLink || (bAdmin ? Links.rootAdmin() : Links.rootUser()); sCustomLogoutLink = sCustomLogoutLink || (bAdmin ? Links.rootAdmin() : Links.rootUser());
if (bLogout && window.location.href !== sCustomLogoutLink) if (bLogout && window.location.href !== sCustomLogoutLink)
@ -267,7 +260,7 @@
else else
{ {
kn.routeOff(); kn.routeOff();
kn.setHash(Links.root(sStartupUrl), true); kn.setHash(Links.root(), true);
kn.routeOff(); kn.routeOff();
_.delay(function () { _.delay(function () {

View file

@ -1273,6 +1273,7 @@
self = this, self = this,
$LAB = require('$LAB'), $LAB = require('$LAB'),
sJsHash = Settings.settingsGet('JsHash'), sJsHash = Settings.settingsGet('JsHash'),
sStartupUrl = Utils.pString(Settings.settingsGet('StartupUrl')),
iContactsSyncInterval = Utils.pInt(Settings.settingsGet('ContactsSyncInterval')), iContactsSyncInterval = Utils.pInt(Settings.settingsGet('ContactsSyncInterval')),
bGoogle = Settings.settingsGet('AllowGoogleSocial'), bGoogle = Settings.settingsGet('AllowGoogleSocial'),
bFacebook = Settings.settingsGet('AllowFacebookSocial'), bFacebook = Settings.settingsGet('AllowFacebookSocial'),
@ -1314,6 +1315,13 @@
if (bValue) if (bValue)
{ {
if ('' !== sStartupUrl)
{
kn.routeOff();
kn.setHash(Links.root(sStartupUrl), true);
kn.routeOn();
}
if ($LAB && window.crypto && window.crypto.getRandomValues && Settings.capa(Enums.Capa.OpenPGP)) if ($LAB && window.crypto && window.crypto.getRandomValues && Settings.capa(Enums.Capa.OpenPGP))
{ {
var fOpenpgpCallback = function (openpgp) { var fOpenpgpCallback = function (openpgp) {

View file

@ -79,7 +79,8 @@
'AttachmentThumbnails': 'ATTACHMENT_THUMBNAILS', 'AttachmentThumbnails': 'ATTACHMENT_THUMBNAILS',
'Templates': 'TEMPLATES', 'Templates': 'TEMPLATES',
'AutoLogout': 'AUTOLOGOUT', 'AutoLogout': 'AUTOLOGOUT',
'AdditionalAccounts': 'ADDITIONAL_ACCOUNTS' 'AdditionalAccounts': 'ADDITIONAL_ACCOUNTS',
'Identities': 'IDENTITIES'
}; };
/** /**

View file

@ -56,9 +56,12 @@
'SettingsContacts', 'SETTINGS_LABELS/LABEL_CONTACTS_NAME', 'contacts'); 'SettingsContacts', 'SETTINGS_LABELS/LABEL_CONTACTS_NAME', 'contacts');
} }
if (Settings.capa(Enums.Capa.AdditionalAccounts) || Settings.capa(Enums.Capa.Identities))
{
kn.addSettingsViewModel(require('Settings/User/Accounts'), 'SettingsAccounts', kn.addSettingsViewModel(require('Settings/User/Accounts'), 'SettingsAccounts',
Settings.capa(Enums.Capa.AdditionalAccounts) ? Settings.capa(Enums.Capa.AdditionalAccounts) ?
'SETTINGS_LABELS/LABEL_ACCOUNTS_NAME' : 'SETTINGS_LABELS/LABEL_IDENTITIES_NAME', 'accounts'); 'SETTINGS_LABELS/LABEL_ACCOUNTS_NAME' : 'SETTINGS_LABELS/LABEL_IDENTITIES_NAME', 'accounts');
}
if (Settings.capa(Enums.Capa.Sieve)) if (Settings.capa(Enums.Capa.Sieve))
{ {

View file

@ -37,6 +37,7 @@
this.capaUserBackground = CapaAdminStore.userBackground; this.capaUserBackground = CapaAdminStore.userBackground;
this.capaGravatar = CapaAdminStore.gravatar; this.capaGravatar = CapaAdminStore.gravatar;
this.capaAdditionalAccounts = CapaAdminStore.additionalAccounts; this.capaAdditionalAccounts = CapaAdminStore.additionalAccounts;
this.capaIdentities = CapaAdminStore.identities;
this.capaAttachmentThumbnails = CapaAdminStore.attachmentThumbnails; this.capaAttachmentThumbnails = CapaAdminStore.attachmentThumbnails;
this.capaTemplates = CapaAdminStore.templates; this.capaTemplates = CapaAdminStore.templates;
@ -136,6 +137,12 @@
}); });
}); });
self.capaIdentities.subscribe(function (bValue) {
Remote.saveAdminConfig(null, {
'CapaIdentities': bValue ? '1' : '0'
});
});
self.capaTemplates.subscribe(function (bValue) { self.capaTemplates.subscribe(function (bValue) {
Remote.saveAdminConfig(null, { Remote.saveAdminConfig(null, {
'CapaTemplates': bValue ? '1' : '0' 'CapaTemplates': bValue ? '1' : '0'

View file

@ -24,7 +24,7 @@
function AccountsUserSettings() function AccountsUserSettings()
{ {
this.allowAdditionalAccount = Settings.capa(Enums.Capa.AdditionalAccounts); this.allowAdditionalAccount = Settings.capa(Enums.Capa.AdditionalAccounts);
this.allowIdentities = true; this.allowIdentities = Settings.capa(Enums.Capa.Identities);;
this.accounts = AccountStore.accounts; this.accounts = AccountStore.accounts;
this.identities = IdentityStore.identities; this.identities = IdentityStore.identities;

View file

@ -16,9 +16,12 @@
AppStore = require('Stores/User/App'), AppStore = require('Stores/User/App'),
LanguageStore = require('Stores/Language'), LanguageStore = require('Stores/Language'),
SettingsStore = require('Stores/User/Settings'), SettingsStore = require('Stores/User/Settings'),
IdentityStore = require('Stores/User/Identity'),
NotificationStore = require('Stores/User/Notification'), NotificationStore = require('Stores/User/Notification'),
MessageStore = require('Stores/User/Message'), MessageStore = require('Stores/User/Message'),
Settings = require('Storage/Settings'),
Remote = require('Remote/User/Ajax') Remote = require('Remote/User/Ajax')
; ;
@ -62,6 +65,20 @@
this.isAnimationSupported = Globals.bAnimationSupported; this.isAnimationSupported = Globals.bAnimationSupported;
this.identities = IdentityStore.identities;
this.identityMain = ko.computed(function () {
var aList = this.identities();
return Utils.isArray(aList) ? _.find(aList, function (oItem) {
return oItem && '' === oItem.id() ? true : false;
}) : null;
}, this);
this.identityMainDesc = ko.computed(function () {
var oIdentity = this.identityMain();
return oIdentity ? oIdentity.formattedName() : '---';
}, this);
this.editorDefaultTypes = ko.computed(function () { this.editorDefaultTypes = ko.computed(function () {
Translator.trigger(); Translator.trigger();
return [ return [
@ -82,6 +99,15 @@
}, this); }, this);
} }
GeneralUserSettings.prototype.editMainIdentity = function ()
{
var oIdentity = this.identityMain();
if (oIdentity)
{
require('Knoin/Knoin').showScreenPopup(require('View/Popup/Identity'), [oIdentity]);
}
};
GeneralUserSettings.prototype.testSoundNotification = function () GeneralUserSettings.prototype.testSoundNotification = function ()
{ {
NotificationStore.playSoundNotification(true); NotificationStore.playSoundNotification(true);

View file

@ -17,6 +17,7 @@
function CapaAdminStore() function CapaAdminStore()
{ {
this.additionalAccounts = ko.observable(false); this.additionalAccounts = ko.observable(false);
this.identities = ko.observable(false);
this.gravatar = ko.observable(false); this.gravatar = ko.observable(false);
this.attachmentThumbnails = ko.observable(false); this.attachmentThumbnails = ko.observable(false);
this.sieve = ko.observable(false); this.sieve = ko.observable(false);
@ -32,6 +33,7 @@
CapaAdminStore.prototype.populate = function() CapaAdminStore.prototype.populate = function()
{ {
this.additionalAccounts(Settings.capa(Enums.Capa.AdditionalAccounts)); this.additionalAccounts(Settings.capa(Enums.Capa.AdditionalAccounts));
this.identities(Settings.capa(Enums.Capa.Identities));
this.gravatar(Settings.capa(Enums.Capa.Gravatar)); this.gravatar(Settings.capa(Enums.Capa.Gravatar));
this.attachmentThumbnails(Settings.capa(Enums.Capa.AttachmentThumbnails)); this.attachmentThumbnails(Settings.capa(Enums.Capa.AttachmentThumbnails));
this.sieve(Settings.capa(Enums.Capa.Sieve)); this.sieve(Settings.capa(Enums.Capa.Sieve));

View file

@ -899,6 +899,20 @@ END;
return $sResult; return $sResult;
} }
/**
* @param string $sDomain
*
* @return string
*/
public static function GetClearDomainName($sDomain)
{
$sResultDomain = \preg_replace(
'/^(webmail|email|mail|www|imap4|pop3|imap|pop|demo|client|ssl|secure)\./i',
'', $sDomain);
return false === \strpos($sResultDomain, '.') ? $sDomain : $sResultDomain;
}
/** /**
* @param string $sFileName * @param string $sFileName
* *

View file

@ -194,9 +194,8 @@ class Actions
*/ */
public function GetShortLifeSpecAuthToken($iLife = 60) public function GetShortLifeSpecAuthToken($iLife = 60)
{ {
$sToken = $this->getAuthToken(); $aAccountHash = \RainLoop\Utils::DecodeKeyValues($this->getLocalAuthToken());
$aAccountHash = \RainLoop\Utils::DecodeKeyValues($sToken); if (!empty($aAccountHash[0]) && 'token' === $aAccountHash[0] && \is_array($aAccountHash))
if (!empty($aAccountHash[0]) && 'token' === $aAccountHash[0] && is_array($aAccountHash))
{ {
$aAccountHash[10] = \time() + $iLife; $aAccountHash[10] = \time() + $iLife;
return \RainLoop\Utils::EncodeKeyValues($aAccountHash); return \RainLoop\Utils::EncodeKeyValues($aAccountHash);
@ -458,6 +457,18 @@ class Actions
$this->Config()->Get('labs', 'http_client_ip_check_proxy', false)), $sLine); $this->Config()->Get('labs', 'http_client_ip_check_proxy', false)), $sLine);
} }
if (false !== \strpos($sLine, '{request:domain}'))
{
$sLine = \str_replace('{request:domain}',
$this->Http()->GetHost(false, true, true), $sLine);
}
if (false !== \strpos($sLine, '{request:domain-clear}'))
{
$sLine = \str_replace('{request:domain-clear}',
\MailSo\Base\Utils::GetClearDomainName($this->Http()->GetHost(false, true, true)), $sLine);
}
$sLine = \preg_replace('/\{request:([^}]*)\}/i', 'request', $sLine); $sLine = \preg_replace('/\{request:([^}]*)\}/i', 'request', $sLine);
} }
@ -489,8 +500,12 @@ class Actions
{ {
$sEmail = $oAccount->Email(); $sEmail = $oAccount->Email();
$sLine = \str_replace('{user:email}', $sEmail, $sLine); $sLine = \str_replace('{user:email}', $sEmail, $sLine);
$sLine = \str_replace('{user:login}', \MailSo\Base\Utils::GetAccountNameFromEmail($sEmail), $sLine); $sLine = \str_replace('{user:login}',
$sLine = \str_replace('{user:domain}', \MailSo\Base\Utils::GetDomainFromEmail($sEmail), $sLine); \MailSo\Base\Utils::GetAccountNameFromEmail($sEmail), $sLine);
$sLine = \str_replace('{user:domain}',
\MailSo\Base\Utils::GetDomainFromEmail($sEmail), $sLine);
$sLine = \str_replace('{user:domain-clear}',
\MailSo\Base\Utils::GetClearDomainName(\MailSo\Base\Utils::GetDomainFromEmail($sEmail)), $sLine);
} }
} }
@ -552,7 +567,7 @@ class Actions
{ {
if ($oAccount) if ($oAccount)
{ {
$sSpecAuthToken = '_'.$oAccount->GetAuthToken(); $sSpecAuthToken = '_'.$oAccount->GetAuthTokenQ();
$this->SetSpecAuthToken($sSpecAuthToken); $this->SetSpecAuthToken($sSpecAuthToken);
\RainLoop\Utils::SetCookie(self::AUTH_SPEC_TOKEN_KEY, $sSpecAuthToken, 0, '/', null, null, true); \RainLoop\Utils::SetCookie(self::AUTH_SPEC_TOKEN_KEY, $sSpecAuthToken, 0, '/', null, null, true);
@ -560,7 +575,7 @@ class Actions
if ($oAccount->SignMe() && 0 < \strlen($oAccount->SignMeToken())) if ($oAccount->SignMe() && 0 < \strlen($oAccount->SignMeToken()))
{ {
\RainLoop\Utils::SetCookie(self::AUTH_SIGN_ME_TOKEN_KEY, \RainLoop\Utils::SetCookie(self::AUTH_SIGN_ME_TOKEN_KEY,
\RainLoop\Utils::EncodeKeyValues(array( \RainLoop\Utils::EncodeKeyValuesQ(array(
'e' => $oAccount->Email(), 'e' => $oAccount->Email(),
't' => $oAccount->SignMeToken() 't' => $oAccount->SignMeToken()
)), )),
@ -569,9 +584,9 @@ class Actions
$this->StorageProvider()->Put($oAccount, $this->StorageProvider()->Put($oAccount,
\RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG, \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
'sign_me', 'sign_me',
\RainLoop\Utils::EncodeKeyValues(array( \RainLoop\Utils::EncodeKeyValuesQ(array(
'Time' => \time(), 'Time' => \time(),
'AuthToken' => $oAccount->GetAuthToken(), 'AuthToken' => $oAccount->GetAuthTokenQ(),
'SignMetToken' => $oAccount->SignMeToken() 'SignMetToken' => $oAccount->SignMeToken()
)) ))
); );
@ -618,7 +633,7 @@ class Actions
/** /**
* @return string * @return string
*/ */
private function getAuthToken() private function getLocalAuthToken()
{ {
$sToken = $this->GetSpecAuthToken(); $sToken = $this->GetSpecAuthToken();
return !empty($sToken) && '_' === \substr($sToken, 0, 1) ? \substr($sToken, 1) : ''; return !empty($sToken) && '_' === \substr($sToken, 0, 1) ? \substr($sToken, 1) : '';
@ -637,7 +652,7 @@ class Actions
*/ */
public function ClearAdminAuthToken() public function ClearAdminAuthToken()
{ {
$aAdminHash = \RainLoop\Utils::DecodeKeyValues($this->getAdminAuthToken()); $aAdminHash = \RainLoop\Utils::DecodeKeyValuesQ($this->getAdminAuthToken());
if ( if (
!empty($aAdminHash[0]) && !empty($aAdminHash[1]) && !empty($aAdminHash[2]) && !empty($aAdminHash[0]) && !empty($aAdminHash[1]) && !empty($aAdminHash[2]) &&
'token' === $aAdminHash[0] && \md5(APP_SALT) === $aAdminHash[1] 'token' === $aAdminHash[0] && \md5(APP_SALT) === $aAdminHash[1]
@ -1085,7 +1100,7 @@ class Actions
$sRand = ''; $sRand = '';
} }
return '' === $sRand ? '' : \RainLoop\Utils::EncodeKeyValues(array('token', \md5(APP_SALT), $sRand)); return '' === $sRand ? '' : \RainLoop\Utils::EncodeKeyValuesQ(array('token', \md5(APP_SALT), $sRand));
} }
/** /**
@ -1098,7 +1113,7 @@ class Actions
$bResult = false; $bResult = false;
if ($this->Config()->Get('security', 'allow_admin_panel', true)) if ($this->Config()->Get('security', 'allow_admin_panel', true))
{ {
$aAdminHash = \RainLoop\Utils::DecodeKeyValues($this->getAdminAuthToken()); $aAdminHash = \RainLoop\Utils::DecodeKeyValuesQ($this->getAdminAuthToken());
if (!empty($aAdminHash[0]) && !empty($aAdminHash[1]) && !empty($aAdminHash[2]) && if (!empty($aAdminHash[0]) && !empty($aAdminHash[1]) && !empty($aAdminHash[2]) &&
'token' === $aAdminHash[0] && \md5(APP_SALT) === $aAdminHash[1] && 'token' === $aAdminHash[0] && \md5(APP_SALT) === $aAdminHash[1] &&
'' !== $this->Cacher(null, true)->Get(\RainLoop\KeyPathHelper::SessionAdminKey($aAdminHash[2]), '') '' !== $this->Cacher(null, true)->Get(\RainLoop\KeyPathHelper::SessionAdminKey($aAdminHash[2]), '')
@ -1124,7 +1139,7 @@ class Actions
if (!empty($sTo)) if (!empty($sTo))
{ {
\RainLoop\Utils::SetCookie(self::AUTH_MAILTO_TOKEN_KEY, \RainLoop\Utils::SetCookie(self::AUTH_MAILTO_TOKEN_KEY,
\RainLoop\Utils::EncodeKeyValues(array( \RainLoop\Utils::EncodeKeyValuesQ(array(
'Time' => \microtime(true), 'Time' => \microtime(true),
'MailTo' => 'MailTo', 'MailTo' => 'MailTo',
'To' => $sTo 'To' => $sTo
@ -1177,16 +1192,17 @@ class Actions
* @param string $sToken * @param string $sToken
* @param bool $bThrowExceptionOnFalse = true * @param bool $bThrowExceptionOnFalse = true
* @param bool $bValidateShortToken = true * @param bool $bValidateShortToken = true
* @param bool $bQ = false
* *
* @return \RainLoop\Model\Account|bool * @return \RainLoop\Model\Account|bool
* @throws \RainLoop\Exceptions\ClientException * @throws \RainLoop\Exceptions\ClientException
*/ */
public function GetAccountFromCustomToken($sToken, $bThrowExceptionOnFalse = true, $bValidateShortToken = true) public function GetAccountFromCustomToken($sToken, $bThrowExceptionOnFalse = true, $bValidateShortToken = true, $bQ = false)
{ {
$oResult = false; $oResult = false;
if (!empty($sToken)) if (!empty($sToken))
{ {
$aAccountHash = \RainLoop\Utils::DecodeKeyValues($sToken); $aAccountHash = $bQ ? \RainLoop\Utils::DecodeKeyValuesQ($sToken) : \RainLoop\Utils::DecodeKeyValues($sToken);
if (!empty($aAccountHash[0]) && 'token' === $aAccountHash[0] && // simple token validation if (!empty($aAccountHash[0]) && 'token' === $aAccountHash[0] && // simple token validation
8 <= \count($aAccountHash) && // length checking 8 <= \count($aAccountHash) && // length checking
!empty($aAccountHash[7]) && // does short token exist !empty($aAccountHash[7]) && // does short token exist
@ -1236,7 +1252,7 @@ class Actions
$sSignMeToken = \RainLoop\Utils::GetCookie(\RainLoop\Actions::AUTH_SIGN_ME_TOKEN_KEY, ''); $sSignMeToken = \RainLoop\Utils::GetCookie(\RainLoop\Actions::AUTH_SIGN_ME_TOKEN_KEY, '');
if (!empty($sSignMeToken)) if (!empty($sSignMeToken))
{ {
$aTokenData = \RainLoop\Utils::DecodeKeyValues($sSignMeToken); $aTokenData = \RainLoop\Utils::DecodeKeyValuesQ($sSignMeToken);
if (\is_array($aTokenData) && !empty($aTokenData['e']) && !empty($aTokenData['t'])) if (\is_array($aTokenData) && !empty($aTokenData['e']) && !empty($aTokenData['t']))
{ {
$sTokenSettings = $this->StorageProvider()->Get($aTokenData['e'], $sTokenSettings = $this->StorageProvider()->Get($aTokenData['e'],
@ -1246,13 +1262,13 @@ class Actions
if (!empty($sTokenSettings)) if (!empty($sTokenSettings))
{ {
$aSignMeData = \RainLoop\Utils::DecodeKeyValues($sTokenSettings); $aSignMeData = \RainLoop\Utils::DecodeKeyValuesQ($sTokenSettings);
if (\is_array($aSignMeData) && if (\is_array($aSignMeData) &&
!empty($aSignMeData['AuthToken']) && !empty($aSignMeData['AuthToken']) &&
!empty($aSignMeData['SignMetToken']) && !empty($aSignMeData['SignMetToken']) &&
$aSignMeData['SignMetToken'] === $aTokenData['t']) $aSignMeData['SignMetToken'] === $aTokenData['t'])
{ {
$oAccount = $this->GetAccountFromCustomToken($aSignMeData['AuthToken'], false, false); $oAccount = $this->GetAccountFromCustomToken($aSignMeData['AuthToken'], false, false, true);
} }
} }
} }
@ -1273,7 +1289,7 @@ class Actions
*/ */
public function getAccountFromToken($bThrowExceptionOnFalse = true) public function getAccountFromToken($bThrowExceptionOnFalse = true)
{ {
return $this->GetAccountFromCustomToken($this->getAuthToken(), $bThrowExceptionOnFalse); return $this->GetAccountFromCustomToken($this->getLocalAuthToken(), $bThrowExceptionOnFalse, true, true);
} }
/** /**
@ -1467,9 +1483,10 @@ class Actions
if (null !== $sToken) if (null !== $sToken)
{ {
\RainLoop\Utils::ClearCookie(self::AUTH_MAILTO_TOKEN_KEY); \RainLoop\Utils::ClearCookie(self::AUTH_MAILTO_TOKEN_KEY);
$mMailToData = \RainLoop\Utils::DecodeKeyValues($sToken);
if (\is_array($mMailToData) && !empty($mMailToData['MailTo']) && 'MailTo' === $mMailToData['MailTo'] && $mMailToData = \RainLoop\Utils::DecodeKeyValuesQ($sToken);
!empty($mMailToData['To'])) if (\is_array($mMailToData) && !empty($mMailToData['MailTo']) &&
'MailTo' === $mMailToData['MailTo'] && !empty($mMailToData['To']))
{ {
$aResult['MailToEmail'] = $mMailToData['To']; $aResult['MailToEmail'] = $mMailToData['To'];
} }
@ -1496,6 +1513,8 @@ class Actions
$aResult['WelcomePageUrl'] = ''; $aResult['WelcomePageUrl'] = '';
$aResult['WelcomePageDisplay'] = ''; $aResult['WelcomePageDisplay'] = '';
} }
$aResult['StartupUrl'] = $this->compileLogParams($aResult['StartupUrl'], $oAccount);
} }
else else
{ {
@ -1509,6 +1528,8 @@ class Actions
$aResult['WelcomePageUrl'] = ''; $aResult['WelcomePageUrl'] = '';
$aResult['WelcomePageDisplay'] = ''; $aResult['WelcomePageDisplay'] = '';
$aResult['StartupUrl'] = '';
} }
$aResult['AllowGoogleSocial'] = (bool) $oConfig->Get('social', 'google_enable', false); $aResult['AllowGoogleSocial'] = (bool) $oConfig->Get('social', 'google_enable', false);
@ -2109,51 +2130,27 @@ class Actions
*/ */
private function clientRsaDecryptHelper($sEncryptedData) private function clientRsaDecryptHelper($sEncryptedData)
{ {
$aMatch = array(); // $aMatch = array();
if ('rsa:xxx:' === substr($sEncryptedData, 0, 8) && $this->Config()->Get('security', 'use_rsa_encryption', false)) // if ('rsa:xxx:' === \substr($sEncryptedData, 0, 8) && $this->Config()->Get('security', 'use_rsa_encryption', false))
{ // {
$oLogger = $this->Logger(); // $oLogger = $this->Logger();
$oLogger->Write('Trying to decode encrypted data', \MailSo\Log\Enumerations\Type::INFO, 'RSA'); // $oLogger->Write('Trying to decode encrypted data', \MailSo\Log\Enumerations\Type::INFO, 'RSA');
// $oLogger->HideErrorNotices(true);
$sPrivateKey = file_exists(APP_PRIVATE_DATA.'rsa/private') ? //
\file_get_contents(APP_PRIVATE_DATA.'rsa/private') : ''; // $sData = \trim(\substr($sEncryptedData, 8));
// $sData = \RainLoop\Utils::DecryptStringRSA(\base64_decode($sData));
if (!empty($sPrivateKey)) //
{ // if (false !== $sData && \preg_match('/^[a-z0-9]{32}:(.+):[a-z0-9]{32}$/', $sData, $aMatch) && isset($aMatch[1]))
$sData = \trim(\substr($sEncryptedData, 8)); // {
// $sEncryptedData = $aMatch[1];
if (!\class_exists('Crypt_RSA')) // }
{ // else
\set_include_path(\get_include_path().PATH_SEPARATOR.APP_VERSION_ROOT_PATH.'app/libraries/phpseclib'); // {
include_once 'Crypt/RSA.php'; // $oLogger->Write('Invalid decrypted data', \MailSo\Log\Enumerations\Type::WARNING, 'RSA');
\defined('CRYPT_RSA_MODE') || \define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); // }
} //
// $oLogger->HideErrorNotices(false);
$oLogger->HideErrorNotices(true); // }
$oRsa = new \Crypt_RSA();
$oRsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$oRsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
$oRsa->setPrivateKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$oRsa->loadKey($sPrivateKey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
$sData = $oRsa->decrypt(\base64_decode($sData));
if (\preg_match('/^[a-z0-9]{32}:(.+):[a-z0-9]{32}$/', $sData, $aMatch) && isset($aMatch[1]))
{
$sEncryptedData = $aMatch[1];
}
else
{
$oLogger->Write('Invalid decrypted data', \MailSo\Log\Enumerations\Type::WARNING, 'RSA');
}
$oLogger->HideErrorNotices(false);
}
else
{
$oLogger->Write('Private key is not found', \MailSo\Log\Enumerations\Type::WARNING, 'RSA');
}
}
return $sEncryptedData; return $sEncryptedData;
} }
@ -2290,6 +2287,7 @@ class Actions
1 < \count($aOrder['Accounts'])) 1 < \count($aOrder['Accounts']))
{ {
$aAccounts = \array_merge(\array_flip($aOrder['Accounts']), $aAccounts); $aAccounts = \array_merge(\array_flip($aOrder['Accounts']), $aAccounts);
$aAccounts = \array_filter($aAccounts, function ($sHash) { $aAccounts = \array_filter($aAccounts, function ($sHash) {
return 5 < \strlen($sHash); return 5 < \strlen($sHash);
}); });
@ -2390,10 +2388,11 @@ class Actions
/** /**
* @param \RainLoop\Model\Account $oAccount * @param \RainLoop\Model\Account $oAccount
* @param bool $bAllowIdentities = false
* *
* @return array * @return array
*/ */
public function GetIdentities($oAccount) public function GetIdentities($oAccount, $bAllowIdentities = false)
{ {
$aIdentities = array(); $aIdentities = array();
if ($oAccount) if ($oAccount)
@ -2421,14 +2420,14 @@ class Actions
if ($oItem && $oItem->Validate()) if ($oItem && $oItem->Validate())
{ {
if ('' === $oItem->Id()) if ($oItem->IsAccountIdentities())
{ {
$oItem->SetEmail($oAccount->Email()); $oItem->SetEmail($oAccount->Email());
$bHasAccountIdentity = true; $bHasAccountIdentity = true;
\array_unshift($aIdentities, $oItem); \array_push($aIdentities, $oItem);
} }
else else if ($bAllowIdentities)
{ {
\array_push($aIdentities, $oItem); \array_push($aIdentities, $oItem);
} }
@ -2442,7 +2441,7 @@ class Actions
\RainLoop\Model\Identity::NewInstanceFromAccount($oAccount)); \RainLoop\Model\Identity::NewInstanceFromAccount($oAccount));
} }
if (1 < \count($aIdentities)) if (1 < \count($aIdentities) && $bAllowIdentities)
{ {
$sOrder = $this->StorageProvider()->Get($oAccount, $sOrder = $this->StorageProvider()->Get($oAccount,
\RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG, \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
@ -2454,8 +2453,16 @@ class Actions
1 < \count($aOrder['Identities'])) 1 < \count($aOrder['Identities']))
{ {
$aList = $aOrder['Identities']; $aList = $aOrder['Identities'];
foreach ($aList as $iIndex => $sItem)
{
if ('' === $sItem)
{
$aList[$iIndex] = '---';
}
}
\usort($aIdentities, function ($a, $b) use ($aList) { \usort($aIdentities, function ($a, $b) use ($aList) {
return \array_search($a->Id(), $aList) < \array_search($b->Id(), $aList) ? -1 : 1; return \array_search($a->Id(true), $aList) < \array_search($b->Id(true), $aList) ? -1 : 1;
}); });
} }
} }
@ -2527,14 +2534,20 @@ class Actions
/** /**
* @param \RainLoop\Model\Account $oAccount * @param \RainLoop\Model\Account $oAccount
* @param array $aIdentities = array() * @param array $aIdentities = array()
* @param bool $bAllowIdentities = false
* *
* @return array * @return array
*/ */
public function SetIdentities($oAccount, $aIdentities = array()) public function SetIdentities($oAccount, $aIdentities = array(), $bAllowIdentities = false)
{ {
$aResult = array(); $aResult = array();
foreach ($aIdentities as $oItem) foreach ($aIdentities as $oItem)
{ {
if (!$bAllowIdentities && $oItem && !$oItem->IsAccountIdentities())
{
continue;
}
$aResult[] = $oItem->ToSimpleJSON(false); $aResult[] = $oItem->ToSimpleJSON(false);
} }
@ -2675,7 +2688,7 @@ class Actions
$oNewAccount->SetParentEmail($sParentEmail); $oNewAccount->SetParentEmail($sParentEmail);
$aAccounts[$oNewAccount->Email()] = $oNewAccount->GetAuthToken(); $aAccounts[$oNewAccount->Email()] = $oNewAccount->GetAuthToken();
if (0 === \strlen($oAccount->ParentEmail())) if (!$oAccount->IsAdditionalAccount())
{ {
$aAccounts[$oAccount->Email()] = $oAccount->GetAuthToken(); $aAccounts[$oAccount->Email()] = $oAccount->GetAuthToken();
} }
@ -2824,7 +2837,7 @@ class Actions
$mResult = array( $mResult = array(
'Files' => array(array( 'Files' => array(array(
'FileName' => 'attachments.zip', 'FileName' => 'attachments.zip',
'Hash' => \RainLoop\Utils::EncodeKeyValues(array( 'Hash' => \RainLoop\Utils::EncodeKeyValuesQ(array(
'V' => APP_VERSION, 'V' => APP_VERSION,
'Account' => $oAccount ? \md5($oAccount->Hash()) : '', 'Account' => $oAccount ? \md5($oAccount->Hash()) : '',
'FileName' => 'attachments.zip', 'FileName' => 'attachments.zip',
@ -2912,7 +2925,7 @@ class Actions
{ {
$mResult['Files'][] = array( $mResult['Files'][] = array(
'FileName' => isset($aItem['FileName']) ? $aItem['FileName'] : 'file.dat', 'FileName' => isset($aItem['FileName']) ? $aItem['FileName'] : 'file.dat',
'Hash' => \RainLoop\Utils::EncodeKeyValues($aItem) 'Hash' => \RainLoop\Utils::EncodeKeyValuesQ($aItem)
); );
} }
@ -2943,20 +2956,34 @@ class Actions
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidInputArgument); throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidInputArgument);
} }
$aIdentitiesForSave = array(); $aIdentities = $this->GetIdentities($oAccount,
$this->GetCapa(false, \RainLoop\Enumerations\Capa::IDENTITIES, $oAccount));
$aIdentities = $this->GetIdentities($oAccount); $bAdded = false;
$aIdentitiesForSave = array();
foreach ($aIdentities as $oItem) foreach ($aIdentities as $oItem)
{ {
if ($oItem && $oItem->Id() !== $oIdentity->Id()) if ($oItem)
{
if ($oItem->Id() === $oIdentity->Id())
{
$aIdentitiesForSave[] = $oIdentity;
$bAdded = true;
}
else
{ {
$aIdentitiesForSave[] = $oItem; $aIdentitiesForSave[] = $oItem;
} }
} }
}
if (!$bAdded)
{
$aIdentitiesForSave[] = $oIdentity; $aIdentitiesForSave[] = $oIdentity;
}
return $this->DefaultResponse(__FUNCTION__, $this->SetIdentities($oAccount, $aIdentitiesForSave)); return $this->DefaultResponse(__FUNCTION__, $this->SetIdentities($oAccount, $aIdentitiesForSave,
$this->GetCapa(false, \RainLoop\Enumerations\Capa::IDENTITIES, $oAccount)));
} }
/** /**
@ -2968,6 +2995,11 @@ class Actions
{ {
$oAccount = $this->getAccountFromToken(); $oAccount = $this->getAccountFromToken();
if (!$this->GetCapa(false, \RainLoop\Enumerations\Capa::IDENTITIES, $oAccount))
{
return $this->FalseResponse(__FUNCTION__);
}
$sId = \trim($this->GetActionParam('IdToDelete', '')); $sId = \trim($this->GetActionParam('IdToDelete', ''));
if (empty($sId)) if (empty($sId))
{ {
@ -2975,7 +3007,7 @@ class Actions
} }
$aNew = array(); $aNew = array();
$aIdentities = $this->GetIdentities($oAccount); $aIdentities = $this->GetIdentities($oAccount, $this->GetCapa(false, \RainLoop\Enumerations\Capa::IDENTITIES, $oAccount));
foreach ($aIdentities as $oItem) foreach ($aIdentities as $oItem)
{ {
if ($oItem && $sId !== $oItem->Id()) if ($oItem && $sId !== $oItem->Id())
@ -2984,7 +3016,8 @@ class Actions
} }
} }
return $this->DefaultResponse(__FUNCTION__, $this->SetIdentities($oAccount, $aNew)); return $this->DefaultResponse(__FUNCTION__, $this->SetIdentities($oAccount, $aNew,
$this->GetCapa(false, \RainLoop\Enumerations\Capa::IDENTITIES, $oAccount)));
} }
/** /**
@ -3110,7 +3143,7 @@ class Actions
$aAccounts = $this->GetActionParam('Accounts', null); $aAccounts = $this->GetActionParam('Accounts', null);
$aIdentities = $this->GetActionParam('Identities', null); $aIdentities = $this->GetActionParam('Identities', null);
if (!\is_array($aAccounts) || !\is_array($aIdentities)) if (!\is_array($aAccounts) && !\is_array($aIdentities))
{ {
return $this->FalseResponse(__FUNCTION__); return $this->FalseResponse(__FUNCTION__);
} }
@ -3118,8 +3151,8 @@ class Actions
return $this->DefaultResponse(__FUNCTION__, $this->StorageProvider()->Put($oAccount, return $this->DefaultResponse(__FUNCTION__, $this->StorageProvider()->Put($oAccount,
\RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG, 'accounts_identities_order', \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG, 'accounts_identities_order',
\json_encode(array( \json_encode(array(
'Accounts' => $aAccounts, 'Accounts' => \is_array($aAccounts) ? $aAccounts : array(),
'Identities' => $aIdentities 'Identities' => \is_array($aIdentities) ? $aIdentities : array()
)) ))
)); ));
} }
@ -3134,6 +3167,7 @@ class Actions
$oAccount = $this->getAccountFromToken(); $oAccount = $this->getAccountFromToken();
$mAccounts = false; $mAccounts = false;
if ($this->GetCapa(false, \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS, $oAccount)) if ($this->GetCapa(false, \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS, $oAccount))
{ {
$mAccounts = $this->GetAccounts($oAccount); $mAccounts = $this->GetAccounts($oAccount);
@ -3147,7 +3181,8 @@ class Actions
return $this->DefaultResponse(__FUNCTION__, array( return $this->DefaultResponse(__FUNCTION__, array(
'Accounts' => $mAccounts, 'Accounts' => $mAccounts,
'Identities' => $this->GetIdentities($oAccount) 'Identities' => $this->GetIdentities($oAccount,
$this->GetCapa(false, \RainLoop\Enumerations\Capa::IDENTITIES, $oAccount))
)); ));
} }
@ -3448,6 +3483,9 @@ class Actions
case \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS: case \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS:
$this->setConfigFromParams($oConfig, $sParamName, 'webmail', 'allow_additional_accounts', 'bool'); $this->setConfigFromParams($oConfig, $sParamName, 'webmail', 'allow_additional_accounts', 'bool');
break; break;
case \RainLoop\Enumerations\Capa::IDENTITIES:
$this->setConfigFromParams($oConfig, $sParamName, 'webmail', 'allow_additional_identities', 'bool');
break;
case \RainLoop\Enumerations\Capa::TEMPLATES: case \RainLoop\Enumerations\Capa::TEMPLATES:
$this->setConfigFromParams($oConfig, $sParamName, 'capa', 'templates', 'bool'); $this->setConfigFromParams($oConfig, $sParamName, 'capa', 'templates', 'bool');
break; break;
@ -3560,6 +3598,7 @@ class Actions
}); });
$this->setCapaFromParams($oConfig, 'CapaAdditionalAccounts', \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS); $this->setCapaFromParams($oConfig, 'CapaAdditionalAccounts', \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS);
$this->setCapaFromParams($oConfig, 'CapaIdentities', \RainLoop\Enumerations\Capa::IDENTITIES);
$this->setCapaFromParams($oConfig, 'CapaTemplates', \RainLoop\Enumerations\Capa::TEMPLATES); $this->setCapaFromParams($oConfig, 'CapaTemplates', \RainLoop\Enumerations\Capa::TEMPLATES);
$this->setCapaFromParams($oConfig, 'CapaTwoFactorAuth', \RainLoop\Enumerations\Capa::TWO_FACTOR); $this->setCapaFromParams($oConfig, 'CapaTwoFactorAuth', \RainLoop\Enumerations\Capa::TWO_FACTOR);
$this->setCapaFromParams($oConfig, 'CapaTwoFactorAuthForce', \RainLoop\Enumerations\Capa::TWO_FACTOR_FORCE); $this->setCapaFromParams($oConfig, 'CapaTwoFactorAuthForce', \RainLoop\Enumerations\Capa::TWO_FACTOR_FORCE);
@ -7128,19 +7167,19 @@ class Actions
try try
{ {
$aAttachments = $this->GetActionParam('Attachments', array()); $aAttachments = $this->GetActionParam('Attachments', array());
if (is_array($aAttachments) && 0 < count($aAttachments)) if (\is_array($aAttachments) && 0 < \count($aAttachments))
{ {
$mResult = array(); $mResult = array();
foreach ($aAttachments as $sAttachment) foreach ($aAttachments as $sAttachment)
{ {
$aValues = \RainLoop\Utils::DecodeKeyValues($sAttachment); $aValues = \RainLoop\Utils::DecodeKeyValuesQ($sAttachment);
if (is_array($aValues)) if (\is_array($aValues))
{ {
$sFolder = isset($aValues['Folder']) ? $aValues['Folder'] : ''; $sFolder = isset($aValues['Folder']) ? $aValues['Folder'] : '';
$iUid = (int) isset($aValues['Uid']) ? $aValues['Uid'] : 0; $iUid = (int) isset($aValues['Uid']) ? $aValues['Uid'] : 0;
$sMimeIndex = (string) isset($aValues['MimeIndex']) ? $aValues['MimeIndex'] : ''; $sMimeIndex = (string) isset($aValues['MimeIndex']) ? $aValues['MimeIndex'] : '';
$sTempName = md5($sAttachment); $sTempName = \md5($sAttachment);
if (!$this->FilesProvider()->FileExists($oAccount, $sTempName)) if (!$this->FilesProvider()->FileExists($oAccount, $sTempName))
{ {
$this->MailClient()->MessageMimeStream( $this->MailClient()->MessageMimeStream(
@ -7738,7 +7777,7 @@ class Actions
$aParams = $this->GetActionParam('Params', null); $aParams = $this->GetActionParam('Params', null);
$this->Http()->ServerNoCache(); $this->Http()->ServerNoCache();
$aData = \RainLoop\Utils::DecodeKeyValues($sRawKey); $aData = \RainLoop\Utils::DecodeKeyValuesQ($sRawKey);
if (isset($aParams[0], $aParams[1], $aParams[2]) && if (isset($aParams[0], $aParams[1], $aParams[2]) &&
'Raw' === $aParams[0] && 'FramedView' === $aParams[2] && isset($aData['Framed']) && $aData['Framed'] && $aData['FileName']) 'Raw' === $aParams[0] && 'FramedView' === $aParams[2] && isset($aData['Framed']) && $aData['Framed'] && $aData['FileName'])
{ {
@ -7842,6 +7881,11 @@ class Actions
$aResult[] = \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS; $aResult[] = \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS;
} }
if ($oConfig->Get('webmail', 'allow_additional_identities', false))
{
$aResult[] = \RainLoop\Enumerations\Capa::IDENTITIES;
}
if ($oConfig->Get('security', 'allow_two_factor_auth', false) && if ($oConfig->Get('security', 'allow_two_factor_auth', false) &&
($bAdmin || ($oAccount && !$oAccount->IsAdditionalAccount()))) ($bAdmin || ($oAccount && !$oAccount->IsAdditionalAccount())))
{ {
@ -8399,7 +8443,7 @@ class Actions
$bResult = false; $bResult = false;
if (!empty($sRawKey)) if (!empty($sRawKey))
{ {
$aValues = \RainLoop\Utils::DecodeKeyValues($sRawKey); $aValues = \RainLoop\Utils::DecodeKeyValuesQ($sRawKey);
if (is_array($aValues)) if (is_array($aValues))
{ {
$bResult = $aValues; $bResult = $aValues;
@ -9205,7 +9249,7 @@ class Actions
$sSubject = $mResult['Subject']; $sSubject = $mResult['Subject'];
$mResult['Hash'] = \md5($mResult['Folder'].$mResult['Uid']); $mResult['Hash'] = \md5($mResult['Folder'].$mResult['Uid']);
$mResult['RequestHash'] = \RainLoop\Utils::EncodeKeyValues(array( $mResult['RequestHash'] = \RainLoop\Utils::EncodeKeyValuesQ(array(
'V' => APP_VERSION, 'V' => APP_VERSION,
'Account' => $oAccount ? \md5($oAccount->Hash()) : '', 'Account' => $oAccount ? \md5($oAccount->Hash()) : '',
'Folder' => $mResult['Folder'], 'Folder' => $mResult['Folder'],
@ -9270,7 +9314,7 @@ class Actions
if (!!$this->Config()->Get('labs', 'use_local_proxy_for_external_images', false)) if (!!$this->Config()->Get('labs', 'use_local_proxy_for_external_images', false))
{ {
$fAdditionalExternalFilter = function ($sUrl) { $fAdditionalExternalFilter = function ($sUrl) {
return './?/ProxyExternal/'.\RainLoop\Utils::EncodeKeyValues(array( return './?/ProxyExternal/'.\RainLoop\Utils::EncodeKeyValuesQ(array(
'Rnd' => \md5(\microtime(true)), 'Rnd' => \md5(\microtime(true)),
'Token' => \RainLoop\Utils::GetConnectionToken(), 'Token' => \RainLoop\Utils::GetConnectionToken(),
'Url' => $sUrl 'Url' => $sUrl
@ -9421,7 +9465,7 @@ class Actions
$mResult['IsThumbnail'] = $this->isFileHasThumbnail($mResult['FileName']); $mResult['IsThumbnail'] = $this->isFileHasThumbnail($mResult['FileName']);
} }
$mResult['Download'] = \RainLoop\Utils::EncodeKeyValues(array( $mResult['Download'] = \RainLoop\Utils::EncodeKeyValuesQ(array(
'V' => APP_VERSION, 'V' => APP_VERSION,
'Account' => $oAccount ? \md5($oAccount->Hash()) : '', 'Account' => $oAccount ? \md5($oAccount->Hash()) : '',
'Folder' => $mResult['Folder'], 'Folder' => $mResult['Folder'],

View file

@ -139,7 +139,8 @@ class Api
{ {
$sSsoHash = \MailSo\Base\Utils::Sha1Rand($sEmail.$sPassword); $sSsoHash = \MailSo\Base\Utils::Sha1Rand($sEmail.$sPassword);
return \RainLoop\Api::Actions()->Cacher()->Set(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash), \RainLoop\Utils::EncodeKeyValues(array( return \RainLoop\Api::Actions()->Cacher()->Set(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash),
\RainLoop\Utils::EncodeKeyValuesQ(array(
'Email' => $sEmail, 'Email' => $sEmail,
'Password' => $sPassword, 'Password' => $sPassword,
'AdditionalOptions' => $aAdditionalOptions, 'AdditionalOptions' => $aAdditionalOptions,

View file

@ -70,6 +70,7 @@ class Application extends \RainLoop\Config\AbstractConfig
'allow_languages_on_settings' => array(true, 'Allow language selection on settings screen'), 'allow_languages_on_settings' => array(true, 'Allow language selection on settings screen'),
'allow_additional_accounts' => array(true, ''), 'allow_additional_accounts' => array(true, ''),
'allow_additional_identities' => array(true, ''),
'messages_per_page' => array(20, ' Number of messages displayed on page by default'), 'messages_per_page' => array(20, ' Number of messages displayed on page by default'),

View file

@ -16,6 +16,7 @@ class Capa
const FILTERS = 'FILTERS'; const FILTERS = 'FILTERS';
const ATTACHMENT_THUMBNAILS = 'ATTACHMENT_THUMBNAILS'; const ATTACHMENT_THUMBNAILS = 'ATTACHMENT_THUMBNAILS';
const ADDITIONAL_ACCOUNTS = 'ADDITIONAL_ACCOUNTS'; const ADDITIONAL_ACCOUNTS = 'ADDITIONAL_ACCOUNTS';
const IDENTITIES = 'IDENTITIES';
const TEMPLATES = 'TEMPLATES'; const TEMPLATES = 'TEMPLATES';
const AUTOLOGOUT = 'AUTOLOGOUT'; const AUTOLOGOUT = 'AUTOLOGOUT';
} }

View file

@ -366,6 +366,26 @@ class Account extends \RainLoop\Account // for backward compatibility
)); ));
} }
/**
* @return string
*/
public function GetAuthTokenQ()
{
return \RainLoop\Utils::EncodeKeyValuesQ(array(
'token', // 0
$this->sEmail, // 1
$this->sLogin, // 2
$this->sPassword, // 3
\RainLoop\Utils::Fingerprint(), // 4
$this->sSignMeToken, // 5
$this->sParentEmail, // 6
\RainLoop\Utils::GetShortToken(), // 7
$this->sProxyAuthUser, // 8
$this->sProxyAuthPassword, // 9
0 // 10 // timelife
));
}
/** /**
* @param \RainLoop\Plugins\Manager $oPlugins * @param \RainLoop\Plugins\Manager $oPlugins
* @param \MailSo\Mail\MailClient $oMailClient * @param \MailSo\Mail\MailClient $oMailClient

View file

@ -75,11 +75,13 @@ class Identity
} }
/** /**
* @param bool $bFillOnEmpty = false
*
* @return string * @return string
*/ */
public function Id() public function Id($bFillOnEmpty = false)
{ {
return $this->sId; return $bFillOnEmpty ? ('' === $this->sId ? '---' : $this->sId) : $this->sId;
} }
/** /**
@ -192,4 +194,12 @@ class Identity
{ {
return !empty($this->sEmail); return !empty($this->sEmail);
} }
/**
* @return bool
*/
public function IsAccountIdentities()
{
return '' === $this->Id();
}
} }

View file

@ -429,7 +429,7 @@ class ServiceActions
{ {
$this->oActions->verifyCacheByKey($sData); $this->oActions->verifyCacheByKey($sData);
$aData = \RainLoop\Utils::DecodeKeyValues($sData); $aData = \RainLoop\Utils::DecodeKeyValuesQ($sData);
if (\is_array($aData) && !empty($aData['Token']) && !empty($aData['Url']) && $aData['Token'] === \RainLoop\Utils::GetConnectionToken()) if (\is_array($aData) && !empty($aData['Token']) && !empty($aData['Url']) && $aData['Token'] === \RainLoop\Utils::GetConnectionToken())
{ {
$iCode = 404; $iCode = 404;
@ -892,7 +892,7 @@ class ServiceActions
$sSsoSubData = $this->Cacher()->Get(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash)); $sSsoSubData = $this->Cacher()->Get(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash));
if (!empty($sSsoSubData)) if (!empty($sSsoSubData))
{ {
$mData = \RainLoop\Utils::DecodeKeyValues($sSsoSubData); $mData = \RainLoop\Utils::DecodeKeyValuesQ($sSsoSubData);
$this->Cacher()->Delete(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash)); $this->Cacher()->Delete(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash));
if (\is_array($mData) && !empty($mData['Email']) && isset($mData['Password'], $mData['Time']) && if (\is_array($mData) && !empty($mData['Email']) && isset($mData['Password'], $mData['Time']) &&

View file

@ -6,6 +6,10 @@ class Utils
{ {
static $Cookies = null; static $Cookies = null;
static $RSA = null;
static $RsaKey = null;
/** /**
* @return void * @return void
*/ */
@ -31,6 +35,145 @@ class Utils
return false; return false;
} }
/**
* @return \Crypt_RSA|null
*/
static public function CryptRSA()
{
if (null === \RainLoop\Utils::$RSA)
{
if (!\defined('_phpseclib_'))
{
\set_include_path(\get_include_path().PATH_SEPARATOR.APP_VERSION_ROOT_PATH.'app/libraries/phpseclib');
define('_phpseclib_', true);
}
if (!\class_exists('Crypt_RSA'))
{
include_once 'Crypt/RSA.php';
\defined('CRYPT_RSA_MODE') || \define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
}
if (\class_exists('Crypt_RSA'))
{
$oRsa = new \Crypt_RSA();
$oRsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$oRsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
$oRsa->setPrivateKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$sPrivateKey = \file_exists(APP_PRIVATE_DATA.'rsa/private') ?
\file_get_contents(APP_PRIVATE_DATA.'rsa/private') : '';
if (!empty($sPrivateKey))
{
$oRsa->loadKey($sPrivateKey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
$oRsa->loadKey($oRsa->getPublicKey(), CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
\RainLoop\Utils::$RSA = $oRsa;
}
}
}
return \RainLoop\Utils::$RSA;
}
/**
* @return string
*/
static public function RsaPrivateKey()
{
if (!empty(\RainLoop\Utils::$RsaKey))
{
return \RainLoop\Utils::$RsaKey;
}
\RainLoop\Utils::$RsaKey = \file_exists(APP_PRIVATE_DATA.'rsa/private') ?
\file_get_contents(APP_PRIVATE_DATA.'rsa/private') : '';
\RainLoop\Utils::$RsaKey = \is_string(\RainLoop\Utils::$RsaKey) ? \RainLoop\Utils::$RsaKey : '';
}
/**
* @param string $sString
* @param string $sKey = ''
*
* @return string|false
*/
static public function EncryptStringRSA($sString, $sKey = '')
{
$sResult = '';
$sKey = \md5($sKey);
$sPrivateKey = \RainLoop\Utils::RsaPrivateKey();
if (!empty($sPrivateKey))
{
$oPrivKey = \openssl_pkey_get_private($sPrivateKey);
$oKeyDetails = \openssl_pkey_get_details($oPrivKey);
if (!empty($oKeyDetails['key']) && !empty($oKeyDetails['bits']))
{
$oPubKey = \openssl_pkey_get_public($oKeyDetails['key']);
$iC = (($oKeyDetails['bits'] / 8) - 15);
$aString = \str_split($sString, $iC);
foreach ($aString as $iIndex => $sLine)
{
$sEncrypted = '';
\openssl_public_encrypt($sLine, $sEncrypted, $oPubKey);
$aString[$iIndex] = $sEncrypted;
}
$aString[] = $sKey;
$sResult = @\serialize($aString);
\openssl_free_key($oPubKey);
}
\openssl_free_key($oPrivKey);
}
return $sResult;
}
/**
* @param string $sString
* @param string $sKey = ''
*
* @return string|false
*/
static public function DecryptStringRSA($sString, $sKey = '')
{
$sResult = '';
$sKey = \md5($sKey);
$sPrivateKey = \RainLoop\Utils::RsaPrivateKey();
if (!empty($sPrivateKey) && !empty($sString))
{
$oPrivKey = \openssl_pkey_get_private($sPrivateKey);
$aString = @\unserialize($sString);
if (\is_array($aString))
{
if ($sKey === \array_pop($aString))
{
foreach ($aString as $iIndex => $sLine)
{
$sDecrypted = '';
\openssl_private_decrypt($sLine, $sDecrypted, $oPrivKey);
$aString[$iIndex] = $sDecrypted;
}
$sResult = \implode('', $aString);
}
}
\openssl_free_key($oPrivKey);
}
return $sResult;
}
/** /**
* @param string $sString * @param string $sString
@ -54,6 +197,42 @@ class Utils
return \MailSo\Base\Crypt::XxteaDecrypt($sEncriptedString, $sKey); return \MailSo\Base\Crypt::XxteaDecrypt($sEncriptedString, $sKey);
} }
/**
* @param string $sString
* @param string $sKey
*
* @return string
*/
static public function EncryptStringQ($sString, $sKey)
{
// if (\MailSo\Base\Utils::FunctionExistsAndEnabled('openssl_pkey_get_private'))
// {
// return \RainLoop\Utils::EncryptStringRSA($sString,
// $sKey.'Q'.\RainLoop\Utils::GetShortToken());
// }
return \MailSo\Base\Crypt::XxteaEncrypt($sString,
$sKey.'Q'.\RainLoop\Utils::GetShortToken());
}
/**
* @param string $sEncriptedString
* @param string $sKey
*
* @return string
*/
static public function DecryptStringQ($sEncriptedString, $sKey)
{
// if (\MailSo\Base\Utils::FunctionExistsAndEnabled('openssl_pkey_get_private'))
// {
// return \RainLoop\Utils::DecryptStringRSA($sEncriptedString,
// $sKey.'Q'.\RainLoop\Utils::GetShortToken());
// }
return \MailSo\Base\Crypt::XxteaDecrypt($sEncriptedString,
$sKey.'Q'.\RainLoop\Utils::GetShortToken());
}
/** /**
* @param array $aValues * @param array $aValues
* @param string $sCustomKey = '' * @param string $sCustomKey = ''
@ -63,7 +242,7 @@ class Utils
static public function EncodeKeyValues(array $aValues, $sCustomKey = '') static public function EncodeKeyValues(array $aValues, $sCustomKey = '')
{ {
return \MailSo\Base\Utils::UrlSafeBase64Encode( return \MailSo\Base\Utils::UrlSafeBase64Encode(
\RainLoop\Utils::EncryptString(\serialize($aValues), \md5(APP_SALT.$sCustomKey))); \RainLoop\Utils::EncryptString(@\serialize($aValues), \md5(APP_SALT.$sCustomKey)));
} }
/** /**
@ -74,13 +253,41 @@ class Utils
*/ */
static public function DecodeKeyValues($sEncodedValues, $sCustomKey = '') static public function DecodeKeyValues($sEncodedValues, $sCustomKey = '')
{ {
$aResult = \unserialize( $aResult = @\unserialize(
\RainLoop\Utils::DecryptString( \RainLoop\Utils::DecryptString(
\MailSo\Base\Utils::UrlSafeBase64Decode($sEncodedValues), \md5(APP_SALT.$sCustomKey))); \MailSo\Base\Utils::UrlSafeBase64Decode($sEncodedValues), \md5(APP_SALT.$sCustomKey)));
return \is_array($aResult) ? $aResult : array(); return \is_array($aResult) ? $aResult : array();
} }
/**
* @param array $aValues
* @param string $sCustomKey = ''
*
* @return string
*/
static public function EncodeKeyValuesQ(array $aValues, $sCustomKey = '')
{
return \MailSo\Base\Utils::UrlSafeBase64Encode(
\RainLoop\Utils::EncryptStringQ(
@\serialize($aValues), \md5(APP_SALT.$sCustomKey)));
}
/**
* @param string $sEncodedValues
* @param string $sCustomKey = ''
*
* @return array
*/
static public function DecodeKeyValuesQ($sEncodedValues, $sCustomKey = '')
{
$aResult = @\unserialize(
\RainLoop\Utils::DecryptStringQ(
\MailSo\Base\Utils::UrlSafeBase64Decode($sEncodedValues), \md5(APP_SALT.$sCustomKey)));
return \is_array($aResult) ? $aResult : array();
}
/** /**
* @return string * @return string
*/ */
@ -296,33 +503,33 @@ class Utils
*/ */
public static function GetCookie($sName, $mDefault = null) public static function GetCookie($sName, $mDefault = null)
{ {
if (null === self::$Cookies) if (null === \RainLoop\Utils::$Cookies)
{ {
self::$Cookies = is_array($_COOKIE) ? $_COOKIE : array(); \RainLoop\Utils::$Cookies = is_array($_COOKIE) ? $_COOKIE : array();
} }
return isset(self::$Cookies[$sName]) ? self::$Cookies[$sName] : $mDefault; return isset(\RainLoop\Utils::$Cookies[$sName]) ? \RainLoop\Utils::$Cookies[$sName] : $mDefault;
} }
public static function SetCookie($sName, $sValue = '', $iExpire = 0, $sPath = '/', $sDomain = '', $sSecure = false, $bHttpOnly = false) public static function SetCookie($sName, $sValue = '', $iExpire = 0, $sPath = '/', $sDomain = '', $sSecure = false, $bHttpOnly = false)
{ {
if (null === self::$Cookies) if (null === \RainLoop\Utils::$Cookies)
{ {
self::$Cookies = is_array($_COOKIE) ? $_COOKIE : array(); \RainLoop\Utils::$Cookies = is_array($_COOKIE) ? $_COOKIE : array();
} }
self::$Cookies[$sName] = $sValue; \RainLoop\Utils::$Cookies[$sName] = $sValue;
@\setcookie($sName, $sValue, $iExpire, $sPath, $sDomain, $sSecure, $bHttpOnly); @\setcookie($sName, $sValue, $iExpire, $sPath, $sDomain, $sSecure, $bHttpOnly);
} }
public static function ClearCookie($sName) public static function ClearCookie($sName)
{ {
if (null === self::$Cookies) if (null === \RainLoop\Utils::$Cookies)
{ {
self::$Cookies = is_array($_COOKIE) ? $_COOKIE : array(); \RainLoop\Utils::$Cookies = is_array($_COOKIE) ? $_COOKIE : array();
} }
unset(self::$Cookies[$sName]); unset(\RainLoop\Utils::$Cookies[$sName]);
@\setcookie($sName, '', \time() - 3600 * 24 * 30, '/'); @\setcookie($sName, '', \time() - 3600 * 24 * 30, '/');
} }

View file

@ -56,7 +56,7 @@
* @category Crypt * @category Crypt
* @package Crypt_AES * @package Crypt_AES
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVIII Jim Wigginton * @copyright 2008 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -152,4 +152,56 @@ class Crypt_AES extends Crypt_Rijndael
{ {
return; return;
} }
/**
* Sets the key length
*
* Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
*
* @see Crypt_Rijndael:setKeyLength()
* @access public
* @param Integer $length
*/
function setKeyLength($length)
{
switch ($length) {
case 160:
$length = 192;
break;
case 224:
$length = 256;
}
parent::setKeyLength($length);
}
/**
* Sets the key.
*
* Rijndael supports five different key lengths, AES only supports three.
*
* @see Crypt_Rijndael:setKey()
* @see setKeyLength()
* @access public
* @param String $key
*/
function setKey($key)
{
parent::setKey($key);
if (!$this->explicit_key_length) {
$length = strlen($key);
switch (true) {
case $length <= 16:
$this->key_size = 16;
break;
case $length <= 24:
$this->key_size = 24;
break;
default:
$this->key_size = 32;
}
$this->_setupEngine();
}
}
} }

View file

@ -47,7 +47,7 @@
* @package Crypt_Base * @package Crypt_Base
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com> * @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */

View file

@ -48,7 +48,7 @@
* @package Crypt_Blowfish * @package Crypt_Blowfish
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com> * @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */

View file

@ -53,7 +53,7 @@
* @category Crypt * @category Crypt
* @package Crypt_DES * @package Crypt_DES
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */

View file

@ -5,7 +5,7 @@
* *
* Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports the following: * Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports the following:
* *
* md2, md5, md5-96, sha1, sha1-96, sha256, sha384, and sha512 * md2, md5, md5-96, sha1, sha1-96, sha256, sha256-96, sha384, and sha512, sha512-96
* *
* If {@link Crypt_Hash::setKey() setKey()} is called, {@link Crypt_Hash::hash() hash()} will return the HMAC as opposed to * If {@link Crypt_Hash::setKey() setKey()} is called, {@link Crypt_Hash::hash() hash()} will return the HMAC as opposed to
* the hash. If no valid algorithm is provided, sha1 will be used. * the hash. If no valid algorithm is provided, sha1 will be used.
@ -49,7 +49,7 @@
* @category Crypt * @category Crypt
* @package Crypt_Hash * @package Crypt_Hash
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -207,6 +207,9 @@ class Crypt_Hash
switch ($hash) { switch ($hash) {
case 'md5-96': case 'md5-96':
case 'sha1-96': case 'sha1-96':
case 'sha256-96':
case 'sha512-96':
$hash = substr($hash, 0, -3);
$this->l = 12; // 96 / 8 = 12 $this->l = 12; // 96 / 8 = 12
break; break;
case 'md2': case 'md2':
@ -243,14 +246,12 @@ class Crypt_Hash
case CRYPT_HASH_MODE_MHASH: case CRYPT_HASH_MODE_MHASH:
switch ($hash) { switch ($hash) {
case 'md5': case 'md5':
case 'md5-96':
$this->hash = MHASH_MD5; $this->hash = MHASH_MD5;
break; break;
case 'sha256': case 'sha256':
$this->hash = MHASH_SHA256; $this->hash = MHASH_SHA256;
break; break;
case 'sha1': case 'sha1':
case 'sha1-96':
default: default:
$this->hash = MHASH_SHA1; $this->hash = MHASH_SHA1;
} }
@ -258,7 +259,6 @@ class Crypt_Hash
case CRYPT_HASH_MODE_HASH: case CRYPT_HASH_MODE_HASH:
switch ($hash) { switch ($hash) {
case 'md5': case 'md5':
case 'md5-96':
$this->hash = 'md5'; $this->hash = 'md5';
return; return;
case 'md2': case 'md2':
@ -268,7 +268,6 @@ class Crypt_Hash
$this->hash = $hash; $this->hash = $hash;
return; return;
case 'sha1': case 'sha1':
case 'sha1-96':
default: default:
$this->hash = 'sha1'; $this->hash = 'sha1';
} }
@ -281,7 +280,6 @@ class Crypt_Hash
$this->hash = array($this, '_md2'); $this->hash = array($this, '_md2');
break; break;
case 'md5': case 'md5':
case 'md5-96':
$this->b = 64; $this->b = 64;
$this->hash = array($this, '_md5'); $this->hash = array($this, '_md5');
break; break;
@ -295,7 +293,6 @@ class Crypt_Hash
$this->hash = array($this, '_sha512'); $this->hash = array($this, '_sha512');
break; break;
case 'sha1': case 'sha1':
case 'sha1-96':
default: default:
$this->b = 64; $this->b = 64;
$this->hash = array($this, '_sha1'); $this->hash = array($this, '_sha1');

View file

@ -55,7 +55,7 @@
* @category Crypt * @category Crypt
* @package Crypt_RC4 * @package Crypt_RC4
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */

View file

@ -62,7 +62,7 @@
* @category Crypt * @category Crypt
* @package Crypt_RSA * @package Crypt_RSA
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMIX Jim Wigginton * @copyright 2009 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -493,14 +493,13 @@ class Crypt_RSA
$this->configFile = CRYPT_RSA_OPENSSL_CONFIG; $this->configFile = CRYPT_RSA_OPENSSL_CONFIG;
if ( !defined('CRYPT_RSA_MODE') ) { if ( !defined('CRYPT_RSA_MODE') ) {
switch (true) {
// Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular, // Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular,
// Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger // Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger
// can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either. // can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either.
if ( defined('MATH_BIGINTEGER_OPENSSL_DISABLE') ) { case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'):
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
} break;
switch ( !defined('CRYPT_RSA_MODE') ) { // ie. only run this if the above didn't set CRYPT_RSA_MODE already
// openssl_pkey_get_details - which is used in the only place Crypt/RSA.php uses OpenSSL - was introduced in PHP 5.2.0 // openssl_pkey_get_details - which is used in the only place Crypt/RSA.php uses OpenSSL - was introduced in PHP 5.2.0
case !function_exists('openssl_pkey_get_details'): case !function_exists('openssl_pkey_get_details'):
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
@ -517,7 +516,14 @@ class Crypt_RSA
$versions = array(); $versions = array();
if (!empty($matches[1])) { if (!empty($matches[1])) {
for ($i = 0; $i < count($matches[1]); $i++) { for ($i = 0; $i < count($matches[1]); $i++) {
$versions[$matches[1][$i]] = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
// Remove letter part in OpenSSL version
if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
$versions[$matches[1][$i]] = $fullVersion;
} else {
$versions[$matches[1][$i]] = $m[0];
}
} }
} }
@ -533,7 +539,7 @@ class Crypt_RSA
define('MATH_BIGINTEGER_OPENSSL_DISABLE', true); define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
} }
break; break;
case true: default:
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
} }
} }
@ -743,17 +749,18 @@ class Crypt_RSA
*/ */
function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients) function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
{ {
$signed = $this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_XML;
$num_primes = count($primes); $num_primes = count($primes);
$raw = array( $raw = array(
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
'modulus' => $n->toBytes(true), 'modulus' => $n->toBytes($signed),
'publicExponent' => $e->toBytes(true), 'publicExponent' => $e->toBytes($signed),
'privateExponent' => $d->toBytes(true), 'privateExponent' => $d->toBytes($signed),
'prime1' => $primes[1]->toBytes(true), 'prime1' => $primes[1]->toBytes($signed),
'prime2' => $primes[2]->toBytes(true), 'prime2' => $primes[2]->toBytes($signed),
'exponent1' => $exponents[1]->toBytes(true), 'exponent1' => $exponents[1]->toBytes($signed),
'exponent2' => $exponents[2]->toBytes(true), 'exponent2' => $exponents[2]->toBytes($signed),
'coefficient' => $coefficients[2]->toBytes(true) 'coefficient' => $coefficients[2]->toBytes($signed)
); );
// if the format in question does not support multi-prime rsa and multi-prime rsa was used, // if the format in question does not support multi-prime rsa and multi-prime rsa was used,
@ -942,8 +949,10 @@ class Crypt_RSA
*/ */
function _convertPublicKey($n, $e) function _convertPublicKey($n, $e)
{ {
$modulus = $n->toBytes(true); $signed = $this->publicKeyFormat != CRYPT_RSA_PUBLIC_FORMAT_XML;
$publicExponent = $e->toBytes(true);
$modulus = $n->toBytes($signed);
$publicExponent = $e->toBytes($signed);
switch ($this->publicKeyFormat) { switch ($this->publicKeyFormat) {
case CRYPT_RSA_PUBLIC_FORMAT_RAW: case CRYPT_RSA_PUBLIC_FORMAT_RAW:

View file

@ -38,7 +38,7 @@
* @category Crypt * @category Crypt
* @package Crypt_Random * @package Crypt_Random
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */

View file

@ -65,7 +65,7 @@
* @category Crypt * @category Crypt
* @package Crypt_Rijndael * @package Crypt_Rijndael
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVIII Jim Wigginton * @copyright 2008 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -702,9 +702,15 @@ class Crypt_Rijndael extends Crypt_Base
case $length <= 16: case $length <= 16:
$this->key_size = 16; $this->key_size = 16;
break; break;
case $length <= 20:
$this->key_size = 20;
break;
case $length <= 24: case $length <= 24:
$this->key_size = 24; $this->key_size = 24;
break; break;
case $length <= 28:
$this->key_size = 28;
break;
default: default:
$this->key_size = 32; $this->key_size = 32;
} }

View file

@ -47,7 +47,7 @@
* @category Crypt * @category Crypt
* @package Crypt_TripleDES * @package Crypt_TripleDES
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */

View file

@ -48,7 +48,7 @@
* @package Crypt_Twofish * @package Crypt_Twofish
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com> * @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */

View file

@ -31,7 +31,7 @@
* @category File * @category File
* @package File_ANSI * @package File_ANSI
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMXII Jim Wigginton * @copyright 2012 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */

View file

@ -34,7 +34,7 @@
* @category File * @category File
* @package File_ASN1 * @package File_ASN1
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMXII Jim Wigginton * @copyright 2012 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -272,7 +272,8 @@ class File_ASN1
} }
$this->encoded = $encoded; $this->encoded = $encoded;
return $this->_decode_ber($encoded); // encapsulate in an array for BC with the old decodeBER
return array($this->_decode_ber($encoded));
} }
/** /**
@ -287,11 +288,8 @@ class File_ASN1
* @return Array * @return Array
* @access private * @access private
*/ */
function _decode_ber(&$encoded, $start = 0) function _decode_ber($encoded, $start = 0)
{ {
$decoded = array();
while ( strlen($encoded) ) {
$current = array('start' => $start); $current = array('start' => $start);
$type = ord($this->_string_shift($encoded)); $type = ord($this->_string_shift($encoded));
@ -317,16 +315,13 @@ class File_ASN1
if ( $length == 0x80 ) { // indefinite length if ( $length == 0x80 ) { // indefinite length
// "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all
// immediately available." -- paragraph 8.1.3.2.c // immediately available." -- paragraph 8.1.3.2.c
//if ( !$constructed ) {
// return false;
//}
$length = strlen($encoded); $length = strlen($encoded);
} elseif ( $length & 0x80 ) { // definite length, long form } elseif ( $length & 0x80 ) { // definite length, long form
// technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only // technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only
// support it up to four. // support it up to four.
$length&= 0x7F; $length&= 0x7F;
$temp = $this->_string_shift($encoded, $length); $temp = $this->_string_shift($encoded, $length);
// tags of indefinite length don't really have a header length; this length includes the tag // tags of indefinte length don't really have a header length; this length includes the tag
$current+= array('headerlength' => $length + 2); $current+= array('headerlength' => $length + 2);
$start+= $length; $start+= $length;
extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4))); extract(unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)));
@ -334,12 +329,10 @@ class File_ASN1
$current+= array('headerlength' => 2); $current+= array('headerlength' => 2);
} }
// End-of-content, see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2
if (!$type && !$length) {
return $decoded;
}
$content = $this->_string_shift($encoded, $length); $content = $this->_string_shift($encoded, $length);
// at this point $length can be overwritten. it's only accurate for definite length things as is
/* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1 /* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1
built-in types. It defines an application-independent data type that must be distinguishable from all other built-in types. It defines an application-independent data type that must be distinguishable from all other
data types. The other three classes are user defined. The APPLICATION class distinguishes data types that data types. The other three classes are user defined. The APPLICATION class distinguishes data types that
@ -354,14 +347,36 @@ class File_ASN1
case FILE_ASN1_CLASS_APPLICATION: case FILE_ASN1_CLASS_APPLICATION:
case FILE_ASN1_CLASS_PRIVATE: case FILE_ASN1_CLASS_PRIVATE:
case FILE_ASN1_CLASS_CONTEXT_SPECIFIC: case FILE_ASN1_CLASS_CONTEXT_SPECIFIC:
$decoded[] = array( if (!$constructed) {
return array(
'type' => $class, 'type' => $class,
'constant' => $tag, 'constant' => $tag,
'content' => $constructed ? $this->_decode_ber($content, $start) : $content, 'content' => $content,
'length' => $length + $start - $current['start'] 'length' => $length + $start - $current['start']
) + $current; );
}
$newcontent = array();
if (strlen($content)) {
$newcontent = $this->_decode_ber($content, $start);
$length = $newcontent['length'];
if (substr($content, $length, 2) == "\0\0") {
$length+= 2;
}
$start+= $length; $start+= $length;
continue 2; $newcontent = array($newcontent);
}
return array(
'type' => $class,
'constant' => $tag,
// the array encapsulation is for BC with the old format
'content' => $newcontent,
// the only time when $content['headerlength'] isn't defined is when the length is indefinite.
// the absence of $content['headerlength'] is how we know if something is indefinite or not.
// technically, it could be defined to be 2 and then another indicator could be used but whatever.
'length' => $start - $current['start']
) + $current;
} }
$current+= array('type' => $tag); $current+= array('type' => $tag);
@ -409,16 +424,21 @@ class File_ASN1
if (!$constructed) { if (!$constructed) {
$current['content'] = $content; $current['content'] = $content;
} else { } else {
$temp = $this->_decode_ber($content, $start); $current['content'] = '';
$length-= strlen($content); $length = 0;
for ($i = 0, $size = count($temp); $i < $size; $i++) { while (substr($content, 0, 2) != "\0\0") {
$temp = $this->_decode_ber($content, $length + $start);
$this->_string_shift($content, $temp['length']);
// all subtags should be octet strings // all subtags should be octet strings
//if ($temp[$i]['type'] != FILE_ASN1_TYPE_OCTET_STRING) { //if ($temp['type'] != FILE_ASN1_TYPE_OCTET_STRING) {
// return false; // return false;
//} //}
$current['content'].= $temp[$i]['content']; $current['content'].= $temp['content'];
$length+= $temp['length'];
}
if (substr($content, 0, 2) == "\0\0") {
$length+= 2; // +2 for the EOC
} }
// $length =
} }
break; break;
case FILE_ASN1_TYPE_NULL: case FILE_ASN1_TYPE_NULL:
@ -429,7 +449,20 @@ class File_ASN1
break; break;
case FILE_ASN1_TYPE_SEQUENCE: case FILE_ASN1_TYPE_SEQUENCE:
case FILE_ASN1_TYPE_SET: case FILE_ASN1_TYPE_SET:
$current['content'] = $this->_decode_ber($content, $start); $offset = 0;
$current['content'] = array();
while (strlen($content)) {
// if indefinite length construction was used and we have an end-of-content string next
// see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2
if (!isset($current['headerlength']) && substr($content, 0, 2) == "\0\0") {
$length = $offset + 2; // +2 for the EOC
break 2;
}
$temp = $this->_decode_ber($content, $start + $offset);
$this->_string_shift($content, $temp['length']);
$current['content'][] = $temp;
$offset+= $temp['length'];
}
break; break;
case FILE_ASN1_TYPE_OBJECT_IDENTIFIER: case FILE_ASN1_TYPE_OBJECT_IDENTIFIER:
$temp = ord($this->_string_shift($content)); $temp = ord($this->_string_shift($content));
@ -484,18 +517,16 @@ class File_ASN1
case FILE_ASN1_TYPE_GENERALIZED_TIME: case FILE_ASN1_TYPE_GENERALIZED_TIME:
$current['content'] = $this->_decodeTime($content, $tag); $current['content'] = $this->_decodeTime($content, $tag);
default: default:
} }
$start+= $length; $start+= $length;
$decoded[] = $current + array('length' => $start - $current['start']);
}
return $decoded; // ie. length is the length of the full TLV encoding - it's not just the length of the value
return $current + array('length' => $start - $current['start']);
} }
/** /**
* ASN.1 Decode * ASN.1 Map
* *
* Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format. * Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format.
* *
@ -805,16 +836,6 @@ class File_ASN1
return $this->_encode_der($source, $mapping, null, $special); return $this->_encode_der($source, $mapping, null, $special);
} }
/**
* ASN.1 Encode (Helper function)
*
* @param String $source
* @param Array $mapping
* @param Integer $idx
* @param Array $special
* @return String
* @access private
*/
/** /**
* ASN.1 Encode (Helper function) * ASN.1 Encode (Helper function)
* *

View file

@ -37,7 +37,7 @@
* @category File * @category File
* @package File_X509 * @package File_X509
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMXII Jim Wigginton * @copyright 2012 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */

View file

@ -63,7 +63,7 @@
* @category Math * @category Math
* @package Math_BigInteger * @package Math_BigInteger
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVI Jim Wigginton * @copyright 2006 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger * @link http://pear.php.net/package/Math_BigInteger
*/ */
@ -278,7 +278,14 @@ class Math_BigInteger
$versions = array(); $versions = array();
if (!empty($matches[1])) { if (!empty($matches[1])) {
for ($i = 0; $i < count($matches[1]); $i++) { for ($i = 0; $i < count($matches[1]); $i++) {
$versions[$matches[1][$i]] = trim(str_replace('=>', '', strip_tags($matches[2][$i]))); $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
// Remove letter part in OpenSSL version
if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
$versions[$matches[1][$i]] = $fullVersion;
} else {
$versions[$matches[1][$i]] = $m[0];
}
} }
} }
@ -329,7 +336,10 @@ class Math_BigInteger
switch ( MATH_BIGINTEGER_MODE ) { switch ( MATH_BIGINTEGER_MODE ) {
case MATH_BIGINTEGER_MODE_GMP: case MATH_BIGINTEGER_MODE_GMP:
if (is_resource($x) && get_resource_type($x) == 'GMP integer') { switch (true) {
case is_resource($x) && get_resource_type($x) == 'GMP integer':
// PHP 5.6 switched GMP from using resources to objects
case is_object($x) && get_class($x) == 'GMP':
$this->value = $x; $this->value = $x;
return; return;
} }
@ -912,7 +922,7 @@ class Math_BigInteger
$value = $x_value; $value = $x_value;
} }
$value[] = 0; // just in case the carry adds an extra digit $value[count($value)] = 0; // just in case the carry adds an extra digit
$carry = 0; $carry = 0;
for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) { for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
@ -2134,7 +2144,7 @@ class Math_BigInteger
if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) { if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) {
$corrector_value = $this->_array_repeat(0, $n_length + 1); $corrector_value = $this->_array_repeat(0, $n_length + 1);
$corrector_value[] = 1; $corrector_value[count($corrector_value)] = 1;
$result = $this->_add($result, false, $corrector_value, false); $result = $this->_add($result, false, $corrector_value, false);
$result = $result[MATH_BIGINTEGER_VALUE]; $result = $result[MATH_BIGINTEGER_VALUE];
} }
@ -2904,7 +2914,7 @@ class Math_BigInteger
$leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3); $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);
$this->_base256_lshift($leading_ones, $current_bits); $this->_base256_lshift($leading_ones, $current_bits);
$temp = str_pad($temp, ceil($this->bits / 8), chr(0), STR_PAD_LEFT); $temp = str_pad($temp, strlen($leading_ones), chr(0), STR_PAD_LEFT);
return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256)); return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256));
} }
@ -3479,7 +3489,7 @@ class Math_BigInteger
} }
if ( $carry ) { if ( $carry ) {
$this->value[] = $carry; $this->value[count($this->value)] = $carry;
} }
while ($num_digits--) { while ($num_digits--) {

View file

@ -44,7 +44,7 @@
* @category Net * @category Net
* @package Net_SCP * @package Net_SCP
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMX Jim Wigginton * @copyright 2010 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -129,7 +129,7 @@ class Net_SCP
} }
switch (strtolower(get_class($ssh))) { switch (strtolower(get_class($ssh))) {
case'net_ssh2': case 'net_ssh2':
$this->mode = NET_SCP_SSH2; $this->mode = NET_SCP_SSH2;
break; break;
case 'net_ssh1': case 'net_ssh1':
@ -170,7 +170,7 @@ class Net_SCP
return false; return false;
} }
if (!$this->ssh->exec('scp -t "' . $remote_file . '"', false)) { // -t = to if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to
return false; return false;
} }
@ -195,7 +195,6 @@ class Net_SCP
$fp = @fopen($data, 'rb'); $fp = @fopen($data, 'rb');
if (!$fp) { if (!$fp) {
fclose($fp);
return false; return false;
} }
$size = filesize($data); $size = filesize($data);
@ -245,7 +244,7 @@ class Net_SCP
return false; return false;
} }
if (!$this->ssh->exec('scp -f "' . $remote_file . '"', false)) { // -f = from if (!$this->ssh->exec('scp -f ' . escapeshellarg($remote_file), false)) { // -f = from
return false; return false;
} }

View file

@ -48,7 +48,7 @@
* @category Net * @category Net
* @package Net_SFTP * @package Net_SFTP
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMIX Jim Wigginton * @copyright 2009 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -1061,12 +1061,14 @@ class Net_SFTP extends Net_SSH2
$dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path)); $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
$temp = &$this->stat_cache; $temp = &$this->stat_cache;
foreach ($dirs as $dir) { $max = count($dirs) - 1;
foreach ($dirs as $i=>$dir) {
if (!isset($temp[$dir])) { if (!isset($temp[$dir])) {
$temp[$dir] = array(); $temp[$dir] = array();
} }
if ($dir == end($dirs)) { if ($i === $max) {
$temp[$dir] = $value; $temp[$dir] = $value;
break;
} }
$temp = &$temp[$dir]; $temp = &$temp[$dir];
} }
@ -1084,8 +1086,9 @@ class Net_SFTP extends Net_SSH2
$dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path)); $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
$temp = &$this->stat_cache; $temp = &$this->stat_cache;
foreach ($dirs as $dir) { $max = count($dirs) - 1;
if ($dir == end($dirs)) { foreach ($dirs as $i=>$dir) {
if ($i === $max) {
unset($temp[$dir]); unset($temp[$dir]);
return true; return true;
} }
@ -1501,7 +1504,7 @@ class Net_SFTP extends Net_SSH2
return false; return false;
} }
$i = 0; $i = 0;
$entries = $this->_list($path, true, false); $entries = $this->_list($path, true);
if ($entries === false) { if ($entries === false) {
return $this->_setstat($path, $attr, false); return $this->_setstat($path, $attr, false);
@ -1513,11 +1516,8 @@ class Net_SFTP extends Net_SSH2
return false; return false;
} }
unset($entries['.'], $entries['..']);
foreach ($entries as $filename=>$props) { foreach ($entries as $filename=>$props) {
if ($filename == '.' || $filename == '..') {
continue;
}
if (!isset($props['type'])) { if (!isset($props['type'])) {
return false; return false;
} }
@ -1757,6 +1757,8 @@ class Net_SFTP extends Net_SSH2
* contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how
* large $remote_file will be, as well. * large $remote_file will be, as well.
* *
* If $data is a resource then it'll be used as a resource instead.
*
* Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take
* care of that, yourself. * care of that, yourself.
* *
@ -1778,7 +1780,7 @@ class Net_SFTP extends Net_SSH2
* Setting $local_start to > 0 or $mode | NET_SFTP_RESUME_START doesn't do anything unless $mode | NET_SFTP_LOCAL_FILE. * Setting $local_start to > 0 or $mode | NET_SFTP_RESUME_START doesn't do anything unless $mode | NET_SFTP_LOCAL_FILE.
* *
* @param String $remote_file * @param String $remote_file
* @param String $data * @param String|resource $data
* @param optional Integer $mode * @param optional Integer $mode
* @param optional Integer $start * @param optional Integer $start
* @param optional Integer $local_start * @param optional Integer $local_start
@ -1834,7 +1836,12 @@ class Net_SFTP extends Net_SSH2
} }
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3 // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3
if ($mode & NET_SFTP_LOCAL_FILE) { switch (true) {
case is_resource($data):
$mode = $mode & ~NET_SFTP_LOCAL_FILE;
$fp = $data;
break;
case $mode & NET_SFTP_LOCAL_FILE:
if (!is_file($data)) { if (!is_file($data)) {
user_error("$data is not a valid file"); user_error("$data is not a valid file");
return false; return false;
@ -1843,7 +1850,11 @@ class Net_SFTP extends Net_SSH2
if (!$fp) { if (!$fp) {
return false; return false;
} }
$size = filesize($data); }
if (isset($fp)) {
$stat = fstat($fp);
$size = $stat['size'];
if ($local_start >= 0) { if ($local_start >= 0) {
fseek($fp, $local_start); fseek($fp, $local_start);
@ -1864,11 +1875,13 @@ class Net_SFTP extends Net_SSH2
$sftp_packet_size-= strlen($handle) + 25; $sftp_packet_size-= strlen($handle) + 25;
$i = 0; $i = 0;
while ($sent < $size) { while ($sent < $size) {
$temp = $mode & NET_SFTP_LOCAL_FILE ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size); $temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size);
$subtemp = $offset + $sent; $subtemp = $offset + $sent;
$packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp); $packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp);
if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) { if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) {
if ($mode & NET_SFTP_LOCAL_FILE) {
fclose($fp); fclose($fp);
}
return false; return false;
} }
$sent+= strlen($temp); $sent+= strlen($temp);
@ -2003,6 +2016,12 @@ class Net_SFTP extends Net_SSH2
return false; return false;
} }
if (is_resource($local_file)) {
$fp = $local_file;
$stat = fstat($fp);
$res_offset = $stat['size'];
} else {
$res_offset = 0;
if ($local_file !== false) { if ($local_file !== false) {
$fp = fopen($local_file, 'wb'); $fp = fopen($local_file, 'wb');
if (!$fp) { if (!$fp) {
@ -2011,13 +2030,16 @@ class Net_SFTP extends Net_SSH2
} else { } else {
$content = ''; $content = '';
} }
}
$fclose_check = $local_file !== false && !is_resource($local_file);
$start = $offset; $start = $offset;
$size = $this->max_sftp_packet < $length || $length < 0 ? $this->max_sftp_packet : $length; $size = $this->max_sftp_packet < $length || $length < 0 ? $this->max_sftp_packet : $length;
while (true) { while (true) {
$packet = pack('Na*N3', strlen($handle), $handle, $offset / 4294967296, $offset, $size); $packet = pack('Na*N3', strlen($handle), $handle, $offset / 4294967296, $offset, $size);
if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) { if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
if ($local_file !== false) { if ($fclose_check) {
fclose($fp); fclose($fp);
} }
return false; return false;
@ -2040,7 +2062,7 @@ class Net_SFTP extends Net_SSH2
break 2; break 2;
default: default:
user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS'); user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS');
if ($local_file !== false) { if ($fclose_check) {
fclose($fp); fclose($fp);
} }
return false; return false;
@ -2055,11 +2077,11 @@ class Net_SFTP extends Net_SSH2
if ($local_file === false) { if ($local_file === false) {
$content = substr($content, 0, $length); $content = substr($content, 0, $length);
} else { } else {
ftruncate($fp, $length); ftruncate($fp, $length + $res_offset);
} }
} }
if ($local_file !== false) { if ($fclose_check) {
fclose($fp); fclose($fp);
} }
@ -2135,7 +2157,7 @@ class Net_SFTP extends Net_SSH2
return false; return false;
} }
$i = 0; $i = 0;
$entries = $this->_list($path, true, false); $entries = $this->_list($path, true);
// normally $entries would have at least . and .. but it might not if the directories // normally $entries would have at least . and .. but it might not if the directories
// permissions didn't allow reading // permissions didn't allow reading
@ -2143,11 +2165,8 @@ class Net_SFTP extends Net_SSH2
return false; return false;
} }
unset($entries['.'], $entries['..']);
foreach ($entries as $filename=>$props) { foreach ($entries as $filename=>$props) {
if ($filename == '.' || $filename == '..') {
continue;
}
if (!isset($props['type'])) { if (!isset($props['type'])) {
return false; return false;
} }
@ -2205,7 +2224,7 @@ class Net_SFTP extends Net_SSH2
$result = $this->_query_stat_cache($path); $result = $this->_query_stat_cache($path);
if (isset($result)) { if (isset($result)) {
// return true if $result is an array or if it's int(1) // return true if $result is an array or if it's an stdClass object
return $result !== false; return $result !== false;
} }
} }
@ -2348,7 +2367,7 @@ class Net_SFTP extends Net_SSH2
} }
switch ($type) { switch ($type) {
case NET_SFTP_BLOCK_DEVICE: return 'block'; case NET_SFTP_TYPE_BLOCK_DEVICE: return 'block';
case NET_SFTP_TYPE_CHAR_DEVICE: return 'char'; case NET_SFTP_TYPE_CHAR_DEVICE: return 'char';
case NET_SFTP_TYPE_DIRECTORY: return 'dir'; case NET_SFTP_TYPE_DIRECTORY: return 'dir';
case NET_SFTP_TYPE_FIFO: return 'fifo'; case NET_SFTP_TYPE_FIFO: return 'fifo';
@ -2454,14 +2473,13 @@ class Net_SFTP extends Net_SSH2
foreach ($this->attributes as $key => $value) { foreach ($this->attributes as $key => $value) {
switch ($flags & $key) { switch ($flags & $key) {
case NET_SFTP_ATTR_SIZE: // 0x00000001 case NET_SFTP_ATTR_SIZE: // 0x00000001
// size is represented by a 64-bit integer, so we perhaps ought to be doing the following: // The size attribute is defined as an unsigned 64-bit integer.
// $attr['size'] = new Math_BigInteger($this->_string_shift($response, 8), 256); // The following will use floats on 32-bit platforms, if necessary.
// of course, you shouldn't be using Net_SFTP to transfer files that are in excess of 4GB // As can be seen in the BigInteger class, floats are generally
// (0xFFFFFFFF bytes), anyway. as such, we'll just represent all file sizes that are bigger than // IEEE 754 binary64 "double precision" on such platforms and
// 4GB as being 4GB. // as such can represent integers of at least 2^50 without loss
extract(unpack('Nupper/Nsize', $this->_string_shift($response, 8))); // of precision. Interpreted in filesize, 2^50 bytes = 1024 TiB.
$attr['size'] = $upper ? 4294967296 * $upper : 0; $attr['size'] = hexdec(bin2hex($this->_string_shift($response, 8)));
$attr['size']+= $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size;
break; break;
case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only) case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only)
$attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8)); $attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8));
@ -2521,7 +2539,7 @@ class Net_SFTP extends Net_SSH2
case 0020000: // character special case 0020000: // character special
return NET_SFTP_TYPE_CHAR_DEVICE; return NET_SFTP_TYPE_CHAR_DEVICE;
case 0060000: // block special case 0060000: // block special
return NET_SFTP_BLOCK_DEVICE; return NET_SFTP_TYPE_BLOCK_DEVICE;
case 0140000: // socket case 0140000: // socket
return NET_SFTP_TYPE_SOCKET; return NET_SFTP_TYPE_SOCKET;
case 0160000: // whiteout case 0160000: // whiteout

View file

@ -28,7 +28,7 @@
* @category Net * @category Net
* @package Net_SFTP_Stream * @package Net_SFTP_Stream
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMXIII Jim Wigginton * @copyright 2013 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -48,7 +48,6 @@ class Net_SFTP_Stream
* Rather than re-create the connection we re-use instances if possible * Rather than re-create the connection we re-use instances if possible
* *
* @var Array * @var Array
* @access static
*/ */
static $instances; static $instances;

View file

@ -59,7 +59,7 @@
* @category Net * @category Net
* @package Net_SSH1 * @package Net_SSH1
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -1128,6 +1128,7 @@ class Net_SSH1
$padding_length = 8 - ($temp['length'] & 7); $padding_length = 8 - ($temp['length'] & 7);
$length = $temp['length'] + $padding_length; $length = $temp['length'] + $padding_length;
$raw = '';
while ($length > 0) { while ($length > 0) {
$temp = fread($this->fsock, $length); $temp = fread($this->fsock, $length);

View file

@ -61,7 +61,7 @@
* @category Net * @category Net
* @package Net_SSH2 * @package Net_SSH2
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMVII Jim Wigginton * @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
*/ */
@ -77,7 +77,7 @@ define('NET_SSH2_MASK_CONNECTED', 0x00000002);
define('NET_SSH2_MASK_LOGIN_REQ', 0x00000004); define('NET_SSH2_MASK_LOGIN_REQ', 0x00000004);
define('NET_SSH2_MASK_LOGIN', 0x00000008); define('NET_SSH2_MASK_LOGIN', 0x00000008);
define('NET_SSH2_MASK_SHELL', 0x00000010); define('NET_SSH2_MASK_SHELL', 0x00000010);
define('NET_SSH2_MASK_WINDOW_ADJUST', 0X00000020); define('NET_SSH2_MASK_WINDOW_ADJUST', 0x00000020);
/**#@-*/ /**#@-*/
/**#@+ /**#@+
@ -191,100 +191,100 @@ class Net_SSH2
* Server Identifier * Server Identifier
* *
* @see Net_SSH2::getServerIdentification() * @see Net_SSH2::getServerIdentification()
* @var String * @var mixed false or Array
* @access private * @access private
*/ */
var $server_identifier = ''; var $server_identifier = false;
/** /**
* Key Exchange Algorithms * Key Exchange Algorithms
* *
* @see Net_SSH2::getKexAlgorithims() * @see Net_SSH2::getKexAlgorithims()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $kex_algorithms; var $kex_algorithms = false;
/** /**
* Server Host Key Algorithms * Server Host Key Algorithms
* *
* @see Net_SSH2::getServerHostKeyAlgorithms() * @see Net_SSH2::getServerHostKeyAlgorithms()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $server_host_key_algorithms; var $server_host_key_algorithms = false;
/** /**
* Encryption Algorithms: Client to Server * Encryption Algorithms: Client to Server
* *
* @see Net_SSH2::getEncryptionAlgorithmsClient2Server() * @see Net_SSH2::getEncryptionAlgorithmsClient2Server()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $encryption_algorithms_client_to_server; var $encryption_algorithms_client_to_server = false;
/** /**
* Encryption Algorithms: Server to Client * Encryption Algorithms: Server to Client
* *
* @see Net_SSH2::getEncryptionAlgorithmsServer2Client() * @see Net_SSH2::getEncryptionAlgorithmsServer2Client()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $encryption_algorithms_server_to_client; var $encryption_algorithms_server_to_client = false;
/** /**
* MAC Algorithms: Client to Server * MAC Algorithms: Client to Server
* *
* @see Net_SSH2::getMACAlgorithmsClient2Server() * @see Net_SSH2::getMACAlgorithmsClient2Server()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $mac_algorithms_client_to_server; var $mac_algorithms_client_to_server = false;
/** /**
* MAC Algorithms: Server to Client * MAC Algorithms: Server to Client
* *
* @see Net_SSH2::getMACAlgorithmsServer2Client() * @see Net_SSH2::getMACAlgorithmsServer2Client()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $mac_algorithms_server_to_client; var $mac_algorithms_server_to_client = false;
/** /**
* Compression Algorithms: Client to Server * Compression Algorithms: Client to Server
* *
* @see Net_SSH2::getCompressionAlgorithmsClient2Server() * @see Net_SSH2::getCompressionAlgorithmsClient2Server()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $compression_algorithms_client_to_server; var $compression_algorithms_client_to_server = false;
/** /**
* Compression Algorithms: Server to Client * Compression Algorithms: Server to Client
* *
* @see Net_SSH2::getCompressionAlgorithmsServer2Client() * @see Net_SSH2::getCompressionAlgorithmsServer2Client()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $compression_algorithms_server_to_client; var $compression_algorithms_server_to_client = false;
/** /**
* Languages: Server to Client * Languages: Server to Client
* *
* @see Net_SSH2::getLanguagesServer2Client() * @see Net_SSH2::getLanguagesServer2Client()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $languages_server_to_client; var $languages_server_to_client = false;
/** /**
* Languages: Client to Server * Languages: Client to Server
* *
* @see Net_SSH2::getLanguagesClient2Server() * @see Net_SSH2::getLanguagesClient2Server()
* @var Array * @var mixed false or Array
* @access private * @access private
*/ */
var $languages_client_to_server; var $languages_client_to_server = false;
/** /**
* Block Size for Server to Client Encryption * Block Size for Server to Client Encryption
@ -949,6 +949,12 @@ class Net_SSH2
*/ */
function _connect() function _connect()
{ {
if ($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) {
return false;
}
$this->bitmap |= NET_SSH2_MASK_CONSTRUCTOR;
$timeout = $this->connectionTimeout; $timeout = $this->connectionTimeout;
$host = $this->host . ':' . $this->port; $host = $this->host . ':' . $this->port;
@ -965,7 +971,7 @@ class Net_SSH2
$timeout-= $elapsed; $timeout-= $elapsed;
if ($timeout <= 0) { if ($timeout <= 0) {
user_error(rtrim("Cannot connect to $host. Timeout error")); user_error("Cannot connect to $host. Timeout error");
return false; return false;
} }
@ -978,7 +984,7 @@ class Net_SSH2
// on windows this returns a "Warning: Invalid CRT parameters detected" error // on windows this returns a "Warning: Invalid CRT parameters detected" error
// the !count() is done as a workaround for <https://bugs.php.net/42682> // the !count() is done as a workaround for <https://bugs.php.net/42682>
if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) { if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
user_error(rtrim("Cannot connect to $host. Banner timeout")); user_error("Cannot connect to $host. Banner timeout");
return false; return false;
} }
@ -1038,7 +1044,7 @@ class Net_SSH2
return false; return false;
} }
$this->bitmap = NET_SSH2_MASK_CONNECTED; $this->bitmap|= NET_SSH2_MASK_CONNECTED;
return true; return true;
} }
@ -1098,7 +1104,7 @@ class Net_SSH2
'arcfour256', 'arcfour256',
'arcfour128', 'arcfour128',
'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key //'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key
// CTR modes from <http://tools.ietf.org/html/rfc4344#section-4>: // CTR modes from <http://tools.ietf.org/html/rfc4344#section-4>:
'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key 'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key
@ -1126,7 +1132,7 @@ class Net_SSH2
'3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode '3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode
'3des-cbc', // REQUIRED three-key 3DES in CBC mode '3des-cbc', // REQUIRED three-key 3DES in CBC mode
'none' // OPTIONAL no encryption; NOT RECOMMENDED //'none' // OPTIONAL no encryption; NOT RECOMMENDED
); );
if (phpseclib_resolve_include_path('Crypt/RC4.php') === false) { if (phpseclib_resolve_include_path('Crypt/RC4.php') === false) {
@ -1163,11 +1169,14 @@ class Net_SSH2
} }
$mac_algorithms = array( $mac_algorithms = array(
// from <http://www.ietf.org/rfc/rfc6668.txt>:
'hmac-sha2-256',// RECOMMENDED HMAC-SHA256 (digest length = key length = 32)
'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20) 'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20)
'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20) 'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20)
'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16) 'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16)
'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16) 'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16)
'none' // OPTIONAL no MAC; NOT RECOMMENDED //'none' // OPTIONAL no MAC; NOT RECOMMENDED
); );
static $compression_algorithms = array( static $compression_algorithms = array(
@ -1692,6 +1701,10 @@ class Net_SSH2
$createKeyLength = 0; // ie. $mac_algorithms[$i] == 'none' $createKeyLength = 0; // ie. $mac_algorithms[$i] == 'none'
switch ($mac_algorithms[$i]) { switch ($mac_algorithms[$i]) {
case 'hmac-sha2-256':
$this->hmac_create = new Crypt_Hash('sha256');
$createKeyLength = 32;
break;
case 'hmac-sha1': case 'hmac-sha1':
$this->hmac_create = new Crypt_Hash('sha1'); $this->hmac_create = new Crypt_Hash('sha1');
$createKeyLength = 20; $createKeyLength = 20;
@ -1718,6 +1731,11 @@ class Net_SSH2
$checkKeyLength = 0; $checkKeyLength = 0;
$this->hmac_size = 0; $this->hmac_size = 0;
switch ($mac_algorithms[$i]) { switch ($mac_algorithms[$i]) {
case 'hmac-sha2-256':
$this->hmac_check = new Crypt_Hash('sha256');
$checkKeyLength = 32;
$this->hmac_size = 32;
break;
case 'hmac-sha1': case 'hmac-sha1':
$this->hmac_check = new Crypt_Hash('sha1'); $this->hmac_check = new Crypt_Hash('sha1');
$checkKeyLength = 20; $checkKeyLength = 20;
@ -1799,7 +1817,6 @@ class Net_SSH2
function _login($username) function _login($username)
{ {
if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) { if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
$this->bitmap |= NET_SSH2_MASK_CONSTRUCTOR;
if (!$this->_connect()) { if (!$this->_connect()) {
return false; return false;
} }
@ -2062,7 +2079,6 @@ class Net_SSH2
if (!count($responses) && $num_prompts) { if (!count($responses) && $num_prompts) {
$this->last_interactive_response = $orig; $this->last_interactive_response = $orig;
$this->bitmap |= NET_SSH_MASK_LOGIN_INTERACTIVE;
return false; return false;
} }
@ -2245,7 +2261,7 @@ class Net_SSH2
/** /**
* Execute Command * Execute Command
* *
* If $block is set to false then Net_SSH2::_get_channel_packet(NET_SSH2_CHANNEL_EXEC) will need to be called manually. * If $callback is set to false then Net_SSH2::_get_channel_packet(NET_SSH2_CHANNEL_EXEC) will need to be called manually.
* In all likelihood, this is not a feature you want to be taking advantage of. * In all likelihood, this is not a feature you want to be taking advantage of.
* *
* @param String $command * @param String $command
@ -2654,11 +2670,12 @@ class Net_SSH2
/** /**
* Is the connection still active? * Is the connection still active?
* *
* @return boolean
* @access public * @access public
*/ */
function isConnected() function isConnected()
{ {
return $this->bitmap & NET_SSH2_MASK_LOGIN; return (bool) ($this->bitmap & NET_SSH2_MASK_CONNECTED);
} }
/** /**
@ -2968,7 +2985,7 @@ class Net_SSH2
extract(unpack('Ctype/Nchannel', $this->_string_shift($response, 5))); extract(unpack('Ctype/Nchannel', $this->_string_shift($response, 5)));
$this->window_size_server_to_client[$channel]-= strlen($response) + 4; $this->window_size_server_to_client[$channel]-= strlen($response);
// resize the window, if appropriate // resize the window, if appropriate
if ($this->window_size_server_to_client[$channel] < 0) { if ($this->window_size_server_to_client[$channel] < 0) {
@ -3258,26 +3275,22 @@ class Net_SSH2
*/ */
function _send_channel_packet($client_channel, $data) function _send_channel_packet($client_channel, $data)
{ {
while (strlen($data)) {
if (!$this->window_size_client_to_server[$client_channel]) {
$this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST;
// using an invalid channel will let the buffers be built up for the valid channels
$this->_get_channel_packet(-1);
$this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST;
}
/* The maximum amount of data allowed is determined by the maximum /* The maximum amount of data allowed is determined by the maximum
packet size for the channel, and the current window size, whichever packet size for the channel, and the current window size, whichever
is smaller. is smaller.
-- http://tools.ietf.org/html/rfc4254#section-5.2 */ -- http://tools.ietf.org/html/rfc4254#section-5.2 */
$max_size = min( $max_size = min(
$this->packet_size_client_to_server[$client_channel], $this->packet_size_client_to_server[$client_channel],
$this->window_size_client_to_server[$client_channel] $this->window_size_client_to_server[$client_channel]
) - 4; );
while (strlen($data) > $max_size) {
if (!$this->window_size_client_to_server[$client_channel]) {
$this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST;
// using an invalid channel will let the buffers be built up for the valid channels
$output = $this->_get_channel_packet(-1);
$this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST;
$max_size = min(
$this->packet_size_client_to_server[$client_channel],
$this->window_size_client_to_server[$client_channel]
) - 4;
}
$temp = $this->_string_shift($data, $max_size); $temp = $this->_string_shift($data, $max_size);
$packet = pack('CN2a*', $packet = pack('CN2a*',
@ -3286,27 +3299,13 @@ class Net_SSH2
strlen($temp), strlen($temp),
$temp $temp
); );
$this->window_size_client_to_server[$client_channel]-= strlen($temp);
$this->window_size_client_to_server[$client_channel]-= strlen($temp) + 4;
if (!$this->_send_binary_packet($packet)) { if (!$this->_send_binary_packet($packet)) {
return false; return false;
} }
} }
if (strlen($data) >= $this->window_size_client_to_server[$client_channel] - 4) { return true;
$this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST;
$this->_get_channel_packet(-1);
$this->bitmap^= NET_SSH2_MASK_WINDOW_ADJUST;
}
$this->window_size_client_to_server[$client_channel]-= strlen($data) + 4;
return $this->_send_binary_packet(pack('CN2a*',
NET_SSH2_MSG_CHANNEL_DATA,
$this->server_channels[$client_channel],
strlen($data),
$data));
} }
/** /**
@ -3355,7 +3354,7 @@ class Net_SSH2
*/ */
function _disconnect($reason) function _disconnect($reason)
{ {
if ($this->bitmap) { if ($this->bitmap & NET_SSH2_MASK_CONNECTED) {
$data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, ''); $data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, '');
$this->_send_binary_packet($data); $this->_send_binary_packet($data);
$this->bitmap = 0; $this->bitmap = 0;
@ -3509,6 +3508,8 @@ class Net_SSH2
*/ */
function getServerIdentification() function getServerIdentification()
{ {
$this->_connect();
return $this->server_identifier; return $this->server_identifier;
} }
@ -3520,6 +3521,8 @@ class Net_SSH2
*/ */
function getKexAlgorithms() function getKexAlgorithms()
{ {
$this->_connect();
return $this->kex_algorithms; return $this->kex_algorithms;
} }
@ -3531,6 +3534,8 @@ class Net_SSH2
*/ */
function getServerHostKeyAlgorithms() function getServerHostKeyAlgorithms()
{ {
$this->_connect();
return $this->server_host_key_algorithms; return $this->server_host_key_algorithms;
} }
@ -3542,6 +3547,8 @@ class Net_SSH2
*/ */
function getEncryptionAlgorithmsClient2Server() function getEncryptionAlgorithmsClient2Server()
{ {
$this->_connect();
return $this->encryption_algorithms_client_to_server; return $this->encryption_algorithms_client_to_server;
} }
@ -3553,6 +3560,8 @@ class Net_SSH2
*/ */
function getEncryptionAlgorithmsServer2Client() function getEncryptionAlgorithmsServer2Client()
{ {
$this->_connect();
return $this->encryption_algorithms_server_to_client; return $this->encryption_algorithms_server_to_client;
} }
@ -3564,6 +3573,8 @@ class Net_SSH2
*/ */
function getMACAlgorithmsClient2Server() function getMACAlgorithmsClient2Server()
{ {
$this->_connect();
return $this->mac_algorithms_client_to_server; return $this->mac_algorithms_client_to_server;
} }
@ -3575,6 +3586,8 @@ class Net_SSH2
*/ */
function getMACAlgorithmsServer2Client() function getMACAlgorithmsServer2Client()
{ {
$this->_connect();
return $this->mac_algorithms_server_to_client; return $this->mac_algorithms_server_to_client;
} }
@ -3586,6 +3599,8 @@ class Net_SSH2
*/ */
function getCompressionAlgorithmsClient2Server() function getCompressionAlgorithmsClient2Server()
{ {
$this->_connect();
return $this->compression_algorithms_client_to_server; return $this->compression_algorithms_client_to_server;
} }
@ -3597,6 +3612,8 @@ class Net_SSH2
*/ */
function getCompressionAlgorithmsServer2Client() function getCompressionAlgorithmsServer2Client()
{ {
$this->_connect();
return $this->compression_algorithms_server_to_client; return $this->compression_algorithms_server_to_client;
} }
@ -3608,6 +3625,8 @@ class Net_SSH2
*/ */
function getLanguagesServer2Client() function getLanguagesServer2Client()
{ {
$this->_connect();
return $this->languages_server_to_client; return $this->languages_server_to_client;
} }
@ -3619,6 +3638,8 @@ class Net_SSH2
*/ */
function getLanguagesClient2Server() function getLanguagesClient2Server()
{ {
$this->_connect();
return $this->languages_client_to_server; return $this->languages_client_to_server;
} }
@ -3648,7 +3669,6 @@ class Net_SSH2
function getServerPublicHostKey() function getServerPublicHostKey()
{ {
if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) { if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
$this->bitmap |= NET_SSH2_MASK_CONSTRUCTOR;
if (!$this->_connect()) { if (!$this->_connect()) {
return false; return false;
} }
@ -3731,8 +3751,9 @@ class Net_SSH2
$e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); $e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
$n = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); $rawN = $this->_string_shift($server_public_host_key, $temp['length']);
$nLength = $temp['length']; $n = new Math_BigInteger($rawN, -256);
$nLength = strlen(ltrim($rawN, "\0"));
/* /*
$temp = unpack('Nlength', $this->_string_shift($signature, 4)); $temp = unpack('Nlength', $this->_string_shift($signature, 4));
@ -3769,7 +3790,7 @@ class Net_SSH2
$s = $s->toBytes(); $s = $s->toBytes();
$h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash)); $h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash));
$h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 3 - strlen($h)) . $h; $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h;
if ($s != $h) { if ($s != $h) {
user_error('Bad server signature'); user_error('Bad server signature');

View file

@ -43,7 +43,7 @@
* @category System * @category System
* @package System_SSH_Agent * @package System_SSH_Agent
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMXIV Jim Wigginton * @copyright 2014 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
* @internal See http://api.libssh.org/rfc/PROTOCOL.agent * @internal See http://api.libssh.org/rfc/PROTOCOL.agent

View file

@ -30,7 +30,7 @@
* @category System * @category System
* @package System_SSH_Agent * @package System_SSH_Agent
* @author Jim Wigginton <terrafrost@php.net> * @author Jim Wigginton <terrafrost@php.net>
* @copyright MMXIV Jim Wigginton * @copyright 2014 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net * @link http://phpseclib.sourceforge.net
* @internal See http://api.libssh.org/rfc/PROTOCOL.agent * @internal See http://api.libssh.org/rfc/PROTOCOL.agent

View file

@ -138,6 +138,13 @@
value: capaAdditionalAccounts value: capaAdditionalAccounts
} }
}"></div> }"></div>
<div data-bind="component: {
name: 'Checkbox',
params: {
label: 'TAB_GENERAL/LABEL_ALLOW_IDENTITIES',
value: capaIdentities
}
}"></div>
</div> </div>
</div> </div>
<!-- <!--

View file

@ -3,6 +3,20 @@
<div class="legend"> <div class="legend">
<span class="i18n i18n-animation" data-i18n="SETTINGS_GENERAL/LEGEND_GENERAL"></span> <span class="i18n i18n-animation" data-i18n="SETTINGS_GENERAL/LEGEND_GENERAL"></span>
</div> </div>
<div class="control-group">
<label class="control-label">
<span class="i18n" data-i18n="SETTINGS_GENERAL/LABEL_IDENTITY"></span>
</label>
<div class="controls">
<div style="display: inline-block; margin-top: 5px">
<b data-bind="text: identityMainDesc"></b>
&nbsp;&nbsp;&nbsp;
<span data-bind="click: editMainIdentity" style="cursor: pointer">
<i class="icon-cog"></i>
</span>
</div>
</div>
</div>
<div class="control-group" data-bind="visible: allowLanguagesOnSettings"> <div class="control-group" data-bind="visible: allowLanguagesOnSettings">
<label class="control-label"> <label class="control-label">
<span class="i18n" data-i18n="SETTINGS_GENERAL/LABEL_LANGUAGE"></span> <span class="i18n" data-i18n="SETTINGS_GENERAL/LABEL_LANGUAGE"></span>

View file

@ -34,6 +34,7 @@ LABEL_ALLOW_GRAVATAR = "Gravatar erlauben"
LEGEND_MAIN = "Haupt" LEGEND_MAIN = "Haupt"
LABEL_ATTACHMENT_SIZE_LIMIT = "Größenlimit für Anhänge" LABEL_ATTACHMENT_SIZE_LIMIT = "Größenlimit für Anhänge"
LABEL_ALLOW_ADDITIONAL_ACCOUNTS = "Zusätzliche Konten erlauben" LABEL_ALLOW_ADDITIONAL_ACCOUNTS = "Zusätzliche Konten erlauben"
LABEL_ALLOW_IDENTITIES = "Allow multiple identities"
LABEL_ALLOW_TEMPLATES = "Vorlagen erlauben" LABEL_ALLOW_TEMPLATES = "Vorlagen erlauben"
ALERT_WARNING = "Warnung!" ALERT_WARNING = "Warnung!"
HTML_ALERT_WEAK_PASSWORD = "Sie verwenden das Standard-Admin-Passwort. HTML_ALERT_WEAK_PASSWORD = "Sie verwenden das Standard-Admin-Passwort.

View file

@ -34,6 +34,7 @@ LABEL_ALLOW_GRAVATAR = "Allow Gravatar"
LEGEND_MAIN = "Main" LEGEND_MAIN = "Main"
LABEL_ATTACHMENT_SIZE_LIMIT = "Attachment size limit" LABEL_ATTACHMENT_SIZE_LIMIT = "Attachment size limit"
LABEL_ALLOW_ADDITIONAL_ACCOUNTS = "Allow additional accounts" LABEL_ALLOW_ADDITIONAL_ACCOUNTS = "Allow additional accounts"
LABEL_ALLOW_IDENTITIES = "Allow multiple identities"
LABEL_ALLOW_TEMPLATES = "Allow templates" LABEL_ALLOW_TEMPLATES = "Allow templates"
ALERT_WARNING = "Warning!" ALERT_WARNING = "Warning!"
HTML_ALERT_WEAK_PASSWORD = "You are using the default admin password. HTML_ALERT_WEAK_PASSWORD = "You are using the default admin password.

View file

@ -34,6 +34,7 @@ LABEL_ALLOW_GRAVATAR = "Permitir Gravatar"
LEGEND_MAIN = "Principal" LEGEND_MAIN = "Principal"
LABEL_ATTACHMENT_SIZE_LIMIT = "Tamanho limite de anexo" LABEL_ATTACHMENT_SIZE_LIMIT = "Tamanho limite de anexo"
LABEL_ALLOW_ADDITIONAL_ACCOUNTS = "Permitir contas adicionais" LABEL_ALLOW_ADDITIONAL_ACCOUNTS = "Permitir contas adicionais"
LABEL_ALLOW_IDENTITIES = "Allow multiple identities"
LABEL_ALLOW_TEMPLATES = "Permitir templates" LABEL_ALLOW_TEMPLATES = "Permitir templates"
ALERT_WARNING = "Aviso!" ALERT_WARNING = "Aviso!"
HTML_ALERT_WEAK_PASSWORD = "Você está usando a senha administrativa padrão. HTML_ALERT_WEAK_PASSWORD = "Você está usando a senha administrativa padrão.

View file

@ -34,6 +34,7 @@ LABEL_ALLOW_GRAVATAR = "Разрешить граватары"
LEGEND_MAIN = "Основное" LEGEND_MAIN = "Основное"
LABEL_ATTACHMENT_SIZE_LIMIT = "Предельный размер вложений" LABEL_ATTACHMENT_SIZE_LIMIT = "Предельный размер вложений"
LABEL_ALLOW_ADDITIONAL_ACCOUNTS = "Разрешить дополнительные аккаунты" LABEL_ALLOW_ADDITIONAL_ACCOUNTS = "Разрешить дополнительные аккаунты"
LABEL_ALLOW_IDENTITIES = "Разрешить множественные профили"
LABEL_ALLOW_TEMPLATES = "Разрешить шаблоны" LABEL_ALLOW_TEMPLATES = "Разрешить шаблоны"
ALERT_WARNING = "Внимание!" ALERT_WARNING = "Внимание!"
HTML_ALERT_WEAK_PASSWORD = "Вы используете пароль администратора по умолчанию. HTML_ALERT_WEAK_PASSWORD = "Вы используете пароль администратора по умолчанию.

View file

@ -481,6 +481,7 @@ AUTOLOGIN_MINUTES_OPTION_NAME = "%MINUTES% minute(s)"
[SETTINGS_GENERAL] [SETTINGS_GENERAL]
LEGEND_GENERAL = "General" LEGEND_GENERAL = "General"
LABEL_LANGUAGE = "Language" LABEL_LANGUAGE = "Language"
LABEL_IDENTITY = "Identity"
LABEL_LAYOUT = "Layout" LABEL_LAYOUT = "Layout"
LABEL_LAYOUT_NO_SPLIT = "No Split" LABEL_LAYOUT_NO_SPLIT = "No Split"
LABEL_LAYOUT_VERTICAL_SPLIT = "Vertical Split" LABEL_LAYOUT_VERTICAL_SPLIT = "Vertical Split"