mirror of
https://github.com/the-djmaze/snappymail.git
synced 2024-09-20 07:35:55 +08:00
CRLF to LF
This commit is contained in:
parent
4468d5bd22
commit
6e0d0b3b6e
|
@ -1,6 +1,7 @@
|
|||
module.exports = {
|
||||
parser: 'babel-eslint',
|
||||
extends: ['eslint:recommended', 'plugin:prettier/recommended'],
|
||||
// extends: ['eslint:recommended', 'plugin:prettier/recommended'],
|
||||
extends: ['eslint:recommended'],
|
||||
plugins: ['prettier'],
|
||||
parserOptions: {
|
||||
ecmaVersion: 6,
|
||||
|
@ -18,8 +19,8 @@ module.exports = {
|
|||
// http://eslint.org/docs/rules/
|
||||
rules: {
|
||||
// plugins
|
||||
'prettier/prettier': 'error',
|
||||
|
||||
// 'prettier/prettier': 'error',
|
||||
'no-mixed-spaces-and-tabs': 'off',
|
||||
'no-console': 'error',
|
||||
'max-len': [
|
||||
'error',
|
||||
|
|
42
_include.php
42
_include.php
|
@ -1,21 +1,21 @@
|
|||
<?php
|
||||
|
||||
// Name this file as "include.php" to enable it.
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function __get_custom_data_full_path()
|
||||
{
|
||||
return '';
|
||||
return '/var/external-rainloop-data-folder/'; // custom data folder path
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function __get_additional_configuration_name()
|
||||
{
|
||||
return '';
|
||||
return defined('APP_SITE') && 0 < strlen(APP_SITE) ? APP_SITE.'.ini' : ''; // additional configuration file name
|
||||
}
|
||||
<?php
|
||||
|
||||
// Name this file as "include.php" to enable it.
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function __get_custom_data_full_path()
|
||||
{
|
||||
return '';
|
||||
return '/var/external-rainloop-data-folder/'; // custom data folder path
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function __get_additional_configuration_name()
|
||||
{
|
||||
return '';
|
||||
return defined('APP_SITE') && 0 < strlen(APP_SITE) ? APP_SITE.'.ini' : ''; // additional configuration file name
|
||||
}
|
||||
|
|
|
@ -1125,8 +1125,7 @@ class AppUser extends AbstractApp {
|
|||
|
||||
let contactsSyncInterval = pInt(Settings.settingsGet('ContactsSyncInterval'));
|
||||
|
||||
const jsHash = Settings.appSettingsGet('jsHash'),
|
||||
startupUrl = pString(Settings.settingsGet('StartupUrl'));
|
||||
const startupUrl = pString(Settings.settingsGet('StartupUrl'));
|
||||
|
||||
if (progressJs) {
|
||||
progressJs.set(90);
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import _ from '_';
|
||||
import { Capa, MessageSetAction } from 'Common/Enums';
|
||||
import { MessageSetAction } from 'Common/Enums';
|
||||
import { trim, pInt, isArray } from 'Common/Utils';
|
||||
import * as Links from 'Common/Links';
|
||||
import * as Settings from 'Storage/Settings';
|
||||
|
||||
let FOLDERS_CACHE = {},
|
||||
FOLDERS_NAME_CACHE = {},
|
||||
|
@ -12,8 +10,7 @@ let FOLDERS_CACHE = {},
|
|||
NEW_MESSAGE_CACHE = {},
|
||||
inboxFolderName = '';
|
||||
|
||||
const REQUESTED_MESSAGE_CACHE = {},
|
||||
capaGravatar = Settings.capa(Capa.Gravatar);
|
||||
const REQUESTED_MESSAGE_CACHE = {};
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
|
@ -33,7 +30,7 @@ export function clear() {
|
|||
*/
|
||||
export function getUserPic(email, callback) {
|
||||
email = trim(email);
|
||||
callback(capaGravatar && '' !== email ? Links.avatarLink(email) : '', email);
|
||||
callback('', email);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -83,11 +83,6 @@ export const bDisableNanoScroll = bMobileDevice;
|
|||
export const bAnimationSupported =
|
||||
!bMobileDevice && $html.hasClass('csstransitions') && $html.hasClass('cssanimations');
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
export const bXMLHttpRequestSupported = !!window.XMLHttpRequest;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
|
|
|
@ -37,7 +37,6 @@ class GeneralAdminSettings {
|
|||
|
||||
this.capaThemes = CapaAdminStore.themes;
|
||||
this.capaUserBackground = CapaAdminStore.userBackground;
|
||||
this.capaGravatar = CapaAdminStore.gravatar;
|
||||
this.capaAdditionalAccounts = CapaAdminStore.additionalAccounts;
|
||||
this.capaIdentities = CapaAdminStore.identities;
|
||||
this.capaAttachmentThumbnails = CapaAdminStore.attachmentThumbnails;
|
||||
|
@ -135,12 +134,6 @@ class GeneralAdminSettings {
|
|||
});
|
||||
});
|
||||
|
||||
this.capaGravatar.subscribe((value) => {
|
||||
Remote.saveAdminConfig(null, {
|
||||
'CapaGravatar': boolToAjax(value)
|
||||
});
|
||||
});
|
||||
|
||||
this.capaAttachmentThumbnails.subscribe((value) => {
|
||||
Remote.saveAdminConfig(null, {
|
||||
'CapaAttachmentThumbnails': boolToAjax(value)
|
||||
|
|
|
@ -6,7 +6,6 @@ class CapaAdminStore {
|
|||
constructor() {
|
||||
this.additionalAccounts = ko.observable(false);
|
||||
this.identities = ko.observable(false);
|
||||
this.gravatar = ko.observable(false);
|
||||
this.attachmentThumbnails = ko.observable(false);
|
||||
this.sieve = ko.observable(false);
|
||||
this.filters = ko.observable(false);
|
||||
|
@ -21,7 +20,6 @@ class CapaAdminStore {
|
|||
populate() {
|
||||
this.additionalAccounts(Settings.capa(Capa.AdditionalAccounts));
|
||||
this.identities(Settings.capa(Capa.Identities));
|
||||
this.gravatar(Settings.capa(Capa.Gravatar));
|
||||
this.attachmentThumbnails(Settings.capa(Capa.AttachmentThumbnails));
|
||||
this.sieve(Settings.capa(Capa.Sieve));
|
||||
this.filters(Settings.capa(Capa.Filters));
|
||||
|
|
|
@ -1,63 +1,63 @@
|
|||
|
||||
.progressjs-theme-rainloop {
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.progressjs-theme-rainloop .progressjs-inner {
|
||||
|
||||
background-color: #939595;
|
||||
position: relative;
|
||||
z-index: 2000;
|
||||
height: 3px;
|
||||
overflow: hidden;
|
||||
|
||||
-webkit-transition: width .5s;
|
||||
-moz-transition: width .5s;
|
||||
-o-transition: width .5s;
|
||||
transition: width .5s;
|
||||
}
|
||||
|
||||
.progressjs-theme-rainloop .progressjs-percent {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: -32px;
|
||||
bottom: 0;
|
||||
|
||||
background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.3)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.3)), color-stop(0.75, rgba(255, 255, 255, 0.3)), color-stop(0.75, transparent), to(transparent));
|
||||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.3) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.3) 50%, rgba(255, 255, 255, 0.3) 75%, transparent 75%, transparent);
|
||||
background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.3) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.3) 50%, rgba(255, 255, 255, 0.3) 75%, transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.3) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.3) 50%, rgba(255, 255, 255, 0.3) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.3) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.3) 50%, rgba(255, 255, 255, 0.3) 75%, transparent 75%, transparent);
|
||||
-webkit-background-size: 32px 32px;
|
||||
-moz-background-size: 32px 32px;
|
||||
-o-background-size: 32px 32px;
|
||||
background-size: 32px 32px;
|
||||
|
||||
-webkit-animation: simple-pace-stripe-animation 500ms linear infinite;
|
||||
-moz-animation: simple-pace-stripe-animation 500ms linear infinite;
|
||||
-ms-animation: simple-pace-stripe-animation 500ms linear infinite;
|
||||
-o-animation: simple-pace-stripe-animation 500ms linear infinite;
|
||||
animation: simple-pace-stripe-animation 500ms linear infinite;
|
||||
}
|
||||
|
||||
@-webkit-keyframes simple-pace-stripe-animation {
|
||||
0% { -webkit-transform: none; transform: none; }
|
||||
100% { -webkit-transform: translate(-32px, 0); transform: translate(-32px, 0); }
|
||||
}
|
||||
@-moz-keyframes simple-pace-stripe-animation {
|
||||
0% { -moz-transform: none; transform: none; }
|
||||
100% { -moz-transform: translate(-32px, 0); transform: translate(-32px, 0); }
|
||||
}
|
||||
@-o-keyframes simple-pace-stripe-animation {
|
||||
0% { -o-transform: none; transform: none; }
|
||||
100% { -o-transform: translate(-32px, 0); transform: translate(-32px, 0); }
|
||||
}
|
||||
@-ms-keyframes simple-pace-stripe-animation {
|
||||
0% { -ms-transform: none; transform: none; }
|
||||
100% { -ms-transform: translate(-32px, 0); transform: translate(-32px, 0); }
|
||||
}
|
||||
@keyframes simple-pace-stripe-animation {
|
||||
0% { transform: none; transform: none; }
|
||||
100% { transform: translate(-32px, 0); transform: translate(-32px, 0); }
|
||||
}
|
||||
|
||||
.progressjs-theme-rainloop {
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.progressjs-theme-rainloop .progressjs-inner {
|
||||
|
||||
background-color: #939595;
|
||||
position: relative;
|
||||
z-index: 2000;
|
||||
height: 3px;
|
||||
overflow: hidden;
|
||||
|
||||
-webkit-transition: width .5s;
|
||||
-moz-transition: width .5s;
|
||||
-o-transition: width .5s;
|
||||
transition: width .5s;
|
||||
}
|
||||
|
||||
.progressjs-theme-rainloop .progressjs-percent {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: -32px;
|
||||
bottom: 0;
|
||||
|
||||
background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.3)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.3)), color-stop(0.75, rgba(255, 255, 255, 0.3)), color-stop(0.75, transparent), to(transparent));
|
||||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.3) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.3) 50%, rgba(255, 255, 255, 0.3) 75%, transparent 75%, transparent);
|
||||
background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.3) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.3) 50%, rgba(255, 255, 255, 0.3) 75%, transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.3) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.3) 50%, rgba(255, 255, 255, 0.3) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.3) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.3) 50%, rgba(255, 255, 255, 0.3) 75%, transparent 75%, transparent);
|
||||
-webkit-background-size: 32px 32px;
|
||||
-moz-background-size: 32px 32px;
|
||||
-o-background-size: 32px 32px;
|
||||
background-size: 32px 32px;
|
||||
|
||||
-webkit-animation: simple-pace-stripe-animation 500ms linear infinite;
|
||||
-moz-animation: simple-pace-stripe-animation 500ms linear infinite;
|
||||
-ms-animation: simple-pace-stripe-animation 500ms linear infinite;
|
||||
-o-animation: simple-pace-stripe-animation 500ms linear infinite;
|
||||
animation: simple-pace-stripe-animation 500ms linear infinite;
|
||||
}
|
||||
|
||||
@-webkit-keyframes simple-pace-stripe-animation {
|
||||
0% { -webkit-transform: none; transform: none; }
|
||||
100% { -webkit-transform: translate(-32px, 0); transform: translate(-32px, 0); }
|
||||
}
|
||||
@-moz-keyframes simple-pace-stripe-animation {
|
||||
0% { -moz-transform: none; transform: none; }
|
||||
100% { -moz-transform: translate(-32px, 0); transform: translate(-32px, 0); }
|
||||
}
|
||||
@-o-keyframes simple-pace-stripe-animation {
|
||||
0% { -o-transform: none; transform: none; }
|
||||
100% { -o-transform: translate(-32px, 0); transform: translate(-32px, 0); }
|
||||
}
|
||||
@-ms-keyframes simple-pace-stripe-animation {
|
||||
0% { -ms-transform: none; transform: none; }
|
||||
100% { -ms-transform: translate(-32px, 0); transform: translate(-32px, 0); }
|
||||
}
|
||||
@keyframes simple-pace-stripe-animation {
|
||||
0% { transform: none; transform: none; }
|
||||
100% { transform: translate(-32px, 0); transform: translate(-32px, 0); }
|
||||
}
|
||||
|
|
|
@ -34,13 +34,13 @@ import {
|
|||
} from 'Common/Utils';
|
||||
|
||||
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
|
||||
import { bXMLHttpRequestSupported, bMobileDevice } from 'Common/Globals';
|
||||
import { upload } from 'Common/Links';
|
||||
import { i18n, getNotification, getUploadErrorDescByCode } from 'Common/Translator';
|
||||
import { format as momentorFormat } from 'Common/Momentor';
|
||||
import { getMessageFlagsFromCache, setMessageFlagsToCache, setFolderHash } from 'Common/Cache';
|
||||
|
||||
import { HtmlEditor } from 'Common/HtmlEditor';
|
||||
import { bMobileDevice } from 'Common/Globals';
|
||||
|
||||
import AppStore from 'Stores/User/App';
|
||||
import SettingsStore from 'Stores/User/Settings';
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import window from 'window';
|
||||
import _ from '_';
|
||||
import ko from 'ko';
|
||||
|
||||
|
@ -11,7 +10,7 @@ import {
|
|||
Notification
|
||||
} from 'Common/Enums';
|
||||
|
||||
import { trim, inArray, pInt, convertLangName, triggerAutocompleteInputChange } from 'Common/Utils';
|
||||
import { trim, inArray, convertLangName, triggerAutocompleteInputChange } from 'Common/Utils';
|
||||
|
||||
import { $win } from 'Common/Globals';
|
||||
import { getNotification, getNotificationFromResponse, reload as translatorReload } from 'Common/Translator';
|
||||
|
@ -289,8 +288,7 @@ class LoginUserView extends AbstractViewNext {
|
|||
|
||||
onBuild() {
|
||||
const signMeLocal = Local.get(ClientSideKeyName.LastSignMe),
|
||||
signMe = (Settings.settingsGet('SignMe') || 'unused').toLowerCase(),
|
||||
jsHash = Settings.appSettingsGet('jsHash');
|
||||
signMe = (Settings.settingsGet('SignMe') || 'unused').toLowerCase();
|
||||
|
||||
switch (signMe) {
|
||||
case LoginSignMeTypeAsString.DefaultOff:
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import window from 'window';
|
||||
import _ from '_';
|
||||
import $ from '$';
|
||||
import ko from 'ko';
|
||||
|
@ -22,7 +21,6 @@ import { $html, leftPanelDisabled, keyScopeReal, useKeyboardShortcuts, moveActio
|
|||
|
||||
import {
|
||||
inArray,
|
||||
isArray,
|
||||
isNonEmptyArray,
|
||||
trim,
|
||||
noop,
|
||||
|
|
38
index.php
38
index.php
|
@ -1,19 +1,19 @@
|
|||
<?php
|
||||
|
||||
if (!defined('APP_VERSION'))
|
||||
{
|
||||
define('APP_VERSION', '0.0.0');
|
||||
define('APP_VERSION_TYPE', 'source');
|
||||
define('APP_INDEX_ROOT_FILE', __FILE__);
|
||||
define('APP_INDEX_ROOT_PATH', str_replace('\\', '/', rtrim(dirname(__FILE__), '\\/').'/'));
|
||||
}
|
||||
|
||||
if (file_exists(APP_INDEX_ROOT_PATH.'rainloop/v/'.APP_VERSION.'/include.php'))
|
||||
{
|
||||
include APP_INDEX_ROOT_PATH.'rainloop/v/'.APP_VERSION.'/include.php';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '[105] Missing version directory';
|
||||
exit(105);
|
||||
}
|
||||
<?php
|
||||
|
||||
if (!defined('APP_VERSION'))
|
||||
{
|
||||
define('APP_VERSION', '0.0.0');
|
||||
define('APP_VERSION_TYPE', 'source');
|
||||
define('APP_INDEX_ROOT_FILE', __FILE__);
|
||||
define('APP_INDEX_ROOT_PATH', str_replace('\\', '/', rtrim(dirname(__FILE__), '\\/').'/'));
|
||||
}
|
||||
|
||||
if (file_exists(APP_INDEX_ROOT_PATH.'rainloop/v/'.APP_VERSION.'/include.php'))
|
||||
{
|
||||
include APP_INDEX_ROOT_PATH.'rainloop/v/'.APP_VERSION.'/include.php';
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '[105] Missing version directory';
|
||||
exit(105);
|
||||
}
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
<?php
|
||||
|
||||
class AddXOriginatingIpHeaderPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
public function Init()
|
||||
{
|
||||
$this->addHook('filter.build-message', 'FilterBuildMessage');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \MailSo\Mime\Message $oMessage
|
||||
*/
|
||||
public function FilterBuildMessage(&$oMessage)
|
||||
{
|
||||
if ($oMessage instanceof \MailSo\Mime\Message)
|
||||
{
|
||||
$sIP = $this->Manager()->Actions()->Http()->GetClientIp(
|
||||
!!$this->Config()->Get('plugin', 'check_proxy', false));
|
||||
|
||||
$oMessage->SetCustomHeader(
|
||||
\MailSo\Mime\Enumerations\Header::X_ORIGINATING_IP,
|
||||
$this->Manager()->Actions()->Http()->IsLocalhost($sIP) ? '127.0.0.1' : $sIP
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('check_proxy')
|
||||
->SetLabel('Сheck User Proxy')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL)
|
||||
->SetDescription('Enable, if you need to check proxy header')
|
||||
->SetDefaultValue(false)
|
||||
);
|
||||
}
|
||||
<?php
|
||||
|
||||
class AddXOriginatingIpHeaderPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
public function Init()
|
||||
{
|
||||
$this->addHook('filter.build-message', 'FilterBuildMessage');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \MailSo\Mime\Message $oMessage
|
||||
*/
|
||||
public function FilterBuildMessage(&$oMessage)
|
||||
{
|
||||
if ($oMessage instanceof \MailSo\Mime\Message)
|
||||
{
|
||||
$sIP = $this->Manager()->Actions()->Http()->GetClientIp(
|
||||
!!$this->Config()->Get('plugin', 'check_proxy', false));
|
||||
|
||||
$oMessage->SetCustomHeader(
|
||||
\MailSo\Mime\Enumerations\Header::X_ORIGINATING_IP,
|
||||
$this->Manager()->Actions()->Http()->IsLocalhost($sIP) ? '127.0.0.1' : $sIP
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('check_proxy')
|
||||
->SetLabel('Сheck User Proxy')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL)
|
||||
->SetDescription('Enable, if you need to check proxy header')
|
||||
->SetDefaultValue(false)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -7,15 +7,15 @@
|
|||
*
|
||||
* Based on:
|
||||
* https://github.com/RainLoop/rainloop-webmail/blob/master/plugins/override-smtp-credentials/index.php
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
class AutoDomainGrabPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
|
||||
|
||||
private $imap_prefix = "mail.";
|
||||
private $smtp_prefix = "mail.";
|
||||
|
||||
|
||||
public function Init()
|
||||
{
|
||||
$this->addHook('filter.smtp-credentials', 'FilterSmtpCredentials');
|
||||
|
@ -41,7 +41,7 @@ class AutoDomainGrabPlugin extends \RainLoop\Plugins\AbstractPlugin
|
|||
{
|
||||
$aImapCredentials['Host'] = $mxhosts[0];
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
$aImapCredentials['Host'] = $this->imap_prefix.$domain;
|
||||
}
|
||||
|
@ -67,8 +67,8 @@ class AutoDomainGrabPlugin extends \RainLoop\Plugins\AbstractPlugin
|
|||
if(getmxrr($domain, $mxhosts) && sizeof($mxhosts) > 0)
|
||||
{
|
||||
$aSmtpCredentials['Host'] = $mxhosts[0];
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
$aSmtpCredentials['Host'] = $this->smtp_prefix.$domain;
|
||||
}
|
||||
|
|
|
@ -1,237 +1,237 @@
|
|||
<?php
|
||||
|
||||
class ChangePasswordCustomSqlDriver implements \RainLoop\Providers\ChangePassword\ChangePasswordInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mHost = '127.0.0.1';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mUser = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mPass = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mDatabase = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mTable = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mSql = '';
|
||||
|
||||
/**
|
||||
* @var \MailSo\Log\Logger
|
||||
*/
|
||||
private $oLogger = null;
|
||||
|
||||
/**
|
||||
* @param string $mHost
|
||||
*
|
||||
* @return \ChangePasswordCustomSqlDriver
|
||||
*/
|
||||
public function SetmHost($mHost)
|
||||
{
|
||||
$this->mHost = $mHost;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mUser
|
||||
*
|
||||
* @return \ChangePasswordCustomSqlDriver
|
||||
*/
|
||||
public function SetmUser($mUser)
|
||||
{
|
||||
$this->mUser = $mUser;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mPass
|
||||
*
|
||||
* @return \ChangePasswordCustomSqlDriver
|
||||
*/
|
||||
public function SetmPass($mPass)
|
||||
{
|
||||
$this->mPass = $mPass;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mDatabase
|
||||
*
|
||||
* @return \ChangePasswordCustomSqlDriver
|
||||
*/
|
||||
public function SetmDatabase($mDatabase)
|
||||
{
|
||||
$this->mDatabase = $mDatabase;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mTable
|
||||
*
|
||||
* @return \ChangePasswordCustomSqlDriver
|
||||
*/
|
||||
public function SetmTable($mTable)
|
||||
{
|
||||
$this->mTable = $mTable;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mSql
|
||||
*
|
||||
* @return \ChangePasswordCustomSqlDriver
|
||||
*/
|
||||
public function SetmSql($mSql)
|
||||
{
|
||||
$this->mSql = $mSql;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \MailSo\Log\Logger $oLogger
|
||||
*
|
||||
* @return \ChangePasswordCustomSqlDriver
|
||||
*/
|
||||
public function SetLogger($oLogger)
|
||||
{
|
||||
if ($oLogger instanceof \MailSo\Log\Logger)
|
||||
{
|
||||
$this->oLogger = $oLogger;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account $oAccount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function PasswordChangePossibility($oAccount)
|
||||
{
|
||||
return $oAccount && $oAccount->Email();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account $oAccount
|
||||
* @param string $sPrevPassword
|
||||
* @param string $sNewPassword
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ChangePassword(\RainLoop\Account $oAccount, $sPrevPassword, $sNewPassword)
|
||||
{
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->Write('Try to change password for '.$oAccount->Email());
|
||||
}
|
||||
|
||||
$bResult = false;
|
||||
|
||||
$dsn = 'mysql:host='.$this->mHost.';dbname='.$this->mDatabase.';charset=utf8';
|
||||
$options = array(
|
||||
PDO::ATTR_EMULATE_PREPARES => true,
|
||||
PDO::ATTR_PERSISTENT => true,
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
|
||||
);
|
||||
|
||||
try
|
||||
{
|
||||
$conn = new PDO($dsn,$this->mUser,$this->mPass,$options);
|
||||
|
||||
//prepare SQL varaibles
|
||||
$sEmail = $oAccount->Email();
|
||||
$sEmailUser = \MailSo\Base\Utils::GetAccountNameFromEmail($sEmail);
|
||||
$sEmailDomain = \MailSo\Base\Utils::GetDomainFromEmail($sEmail);
|
||||
|
||||
// some variables cannot be prepared
|
||||
$this->mSql = str_replace(array(
|
||||
':table'
|
||||
), array(
|
||||
$this->mTable
|
||||
), $this->mSql);
|
||||
|
||||
$placeholders = array(
|
||||
':email' => $sEmail,
|
||||
':oldpass' => $sPrevPassword,
|
||||
':newpass' => $sNewPassword,
|
||||
':domain' => $sEmailDomain,
|
||||
':username' => $sEmailUser
|
||||
);
|
||||
|
||||
// we have to check that all placehoders are used in the query, passing any unused placeholders will generate an error
|
||||
$used_placeholders = array();
|
||||
|
||||
foreach($placeholders as $placeholder => $value) {
|
||||
if(preg_match_all('/'.$placeholder . '(?![a-zA-Z0-9\-])'.'/', $this->mSql) === 1) {
|
||||
// backwards-compabitibility: remove single and double quotes around placeholders
|
||||
$this->mSql = str_replace('`'.$placeholder.'`', $placeholder, $this->mSql);
|
||||
$this->mSql = str_replace("'".$placeholder."'", $placeholder, $this->mSql);
|
||||
$this->mSql = str_replace('"'.$placeholder.'"', $placeholder, $this->mSql);
|
||||
$used_placeholders[$placeholder] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$statement = $conn->prepare($this->mSql);
|
||||
|
||||
// everything is ready (hopefully), bind the values
|
||||
foreach($used_placeholders as $placeholder => $value) {
|
||||
$statement->bindValue($placeholder, $value);
|
||||
}
|
||||
|
||||
// and execute
|
||||
$mSqlReturn = $statement->execute();
|
||||
|
||||
/* can be used for debugging
|
||||
ob_start();
|
||||
$statement->debugDumpParams();
|
||||
$r = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$this->oLogger->Write($r);
|
||||
*/
|
||||
|
||||
if ($mSqlReturn == true)
|
||||
{
|
||||
$bResult = true;
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->Write('Success! Password changed.');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$bResult = false;
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->Write('Something went wrong. Either current password is incorrect, or new password does not match criteria.');
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (\Exception $oException)
|
||||
{
|
||||
$bResult = false;
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->WriteException($oException);
|
||||
}
|
||||
}
|
||||
|
||||
return $bResult;
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
class ChangePasswordCustomSqlDriver implements \RainLoop\Providers\ChangePassword\ChangePasswordInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mHost = '127.0.0.1';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mUser = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mPass = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mDatabase = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mTable = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mSql = '';
|
||||
|
||||
/**
|
||||
* @var \MailSo\Log\Logger
|
||||
*/
|
||||
private $oLogger = null;
|
||||
|
||||
/**
|
||||
* @param string $mHost
|
||||
*
|
||||
* @return \ChangePasswordCustomSqlDriver
|
||||
*/
|
||||
public function SetmHost($mHost)
|
||||
{
|
||||
$this->mHost = $mHost;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mUser
|
||||
*
|
||||
* @return \ChangePasswordCustomSqlDriver
|
||||
*/
|
||||
public function SetmUser($mUser)
|
||||
{
|
||||
$this->mUser = $mUser;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mPass
|
||||
*
|
||||
* @return \ChangePasswordCustomSqlDriver
|
||||
*/
|
||||
public function SetmPass($mPass)
|
||||
{
|
||||
$this->mPass = $mPass;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mDatabase
|
||||
*
|
||||
* @return \ChangePasswordCustomSqlDriver
|
||||
*/
|
||||
public function SetmDatabase($mDatabase)
|
||||
{
|
||||
$this->mDatabase = $mDatabase;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mTable
|
||||
*
|
||||
* @return \ChangePasswordCustomSqlDriver
|
||||
*/
|
||||
public function SetmTable($mTable)
|
||||
{
|
||||
$this->mTable = $mTable;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mSql
|
||||
*
|
||||
* @return \ChangePasswordCustomSqlDriver
|
||||
*/
|
||||
public function SetmSql($mSql)
|
||||
{
|
||||
$this->mSql = $mSql;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \MailSo\Log\Logger $oLogger
|
||||
*
|
||||
* @return \ChangePasswordCustomSqlDriver
|
||||
*/
|
||||
public function SetLogger($oLogger)
|
||||
{
|
||||
if ($oLogger instanceof \MailSo\Log\Logger)
|
||||
{
|
||||
$this->oLogger = $oLogger;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account $oAccount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function PasswordChangePossibility($oAccount)
|
||||
{
|
||||
return $oAccount && $oAccount->Email();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account $oAccount
|
||||
* @param string $sPrevPassword
|
||||
* @param string $sNewPassword
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ChangePassword(\RainLoop\Account $oAccount, $sPrevPassword, $sNewPassword)
|
||||
{
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->Write('Try to change password for '.$oAccount->Email());
|
||||
}
|
||||
|
||||
$bResult = false;
|
||||
|
||||
$dsn = 'mysql:host='.$this->mHost.';dbname='.$this->mDatabase.';charset=utf8';
|
||||
$options = array(
|
||||
PDO::ATTR_EMULATE_PREPARES => true,
|
||||
PDO::ATTR_PERSISTENT => true,
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
|
||||
);
|
||||
|
||||
try
|
||||
{
|
||||
$conn = new PDO($dsn,$this->mUser,$this->mPass,$options);
|
||||
|
||||
//prepare SQL varaibles
|
||||
$sEmail = $oAccount->Email();
|
||||
$sEmailUser = \MailSo\Base\Utils::GetAccountNameFromEmail($sEmail);
|
||||
$sEmailDomain = \MailSo\Base\Utils::GetDomainFromEmail($sEmail);
|
||||
|
||||
// some variables cannot be prepared
|
||||
$this->mSql = str_replace(array(
|
||||
':table'
|
||||
), array(
|
||||
$this->mTable
|
||||
), $this->mSql);
|
||||
|
||||
$placeholders = array(
|
||||
':email' => $sEmail,
|
||||
':oldpass' => $sPrevPassword,
|
||||
':newpass' => $sNewPassword,
|
||||
':domain' => $sEmailDomain,
|
||||
':username' => $sEmailUser
|
||||
);
|
||||
|
||||
// we have to check that all placehoders are used in the query, passing any unused placeholders will generate an error
|
||||
$used_placeholders = array();
|
||||
|
||||
foreach($placeholders as $placeholder => $value) {
|
||||
if(preg_match_all('/'.$placeholder . '(?![a-zA-Z0-9\-])'.'/', $this->mSql) === 1) {
|
||||
// backwards-compabitibility: remove single and double quotes around placeholders
|
||||
$this->mSql = str_replace('`'.$placeholder.'`', $placeholder, $this->mSql);
|
||||
$this->mSql = str_replace("'".$placeholder."'", $placeholder, $this->mSql);
|
||||
$this->mSql = str_replace('"'.$placeholder.'"', $placeholder, $this->mSql);
|
||||
$used_placeholders[$placeholder] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$statement = $conn->prepare($this->mSql);
|
||||
|
||||
// everything is ready (hopefully), bind the values
|
||||
foreach($used_placeholders as $placeholder => $value) {
|
||||
$statement->bindValue($placeholder, $value);
|
||||
}
|
||||
|
||||
// and execute
|
||||
$mSqlReturn = $statement->execute();
|
||||
|
||||
/* can be used for debugging
|
||||
ob_start();
|
||||
$statement->debugDumpParams();
|
||||
$r = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$this->oLogger->Write($r);
|
||||
*/
|
||||
|
||||
if ($mSqlReturn == true)
|
||||
{
|
||||
$bResult = true;
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->Write('Success! Password changed.');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$bResult = false;
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->Write('Something went wrong. Either current password is incorrect, or new password does not match criteria.');
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (\Exception $oException)
|
||||
{
|
||||
$bResult = false;
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->WriteException($oException);
|
||||
}
|
||||
}
|
||||
|
||||
return $bResult;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,53 +1,53 @@
|
|||
<?php
|
||||
|
||||
class ChangePasswordCustomSqlPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
public function Init()
|
||||
{
|
||||
$this->addHook('main.fabrica', 'MainFabrica');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sName
|
||||
* @param mixed $oProvider
|
||||
*/
|
||||
public function MainFabrica($sName, &$oProvider)
|
||||
{
|
||||
switch ($sName)
|
||||
{
|
||||
case 'change-password':
|
||||
include_once __DIR__.'/ChangePasswordCustomSqlDriver.php';
|
||||
$oProvider = new ChangePasswordCustomSqlDriver();
|
||||
$oProvider
|
||||
->SetLogger($this->Manager()->Actions()->Logger())
|
||||
->SetmHost($this->Config()->Get('plugin', 'mHost', ''))
|
||||
->SetmUser($this->Config()->Get('plugin', 'mUser', ''))
|
||||
->SetmPass($this->Config()->Get('plugin', 'mPass', ''))
|
||||
->SetmDatabase($this->Config()->Get('plugin', 'mDatabase', ''))
|
||||
->SetmTable($this->Config()->Get('plugin', 'mTable', ''))
|
||||
->SetmSql($this->Config()->Get('plugin', 'mSql', ''))
|
||||
;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('mHost')->SetLabel('MySQL Host')
|
||||
->SetDefaultValue('127.0.0.1'),
|
||||
\RainLoop\Plugins\Property::NewInstance('mUser')->SetLabel('MySQL User'),
|
||||
\RainLoop\Plugins\Property::NewInstance('mPass')->SetLabel('MySQL Password')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD),
|
||||
\RainLoop\Plugins\Property::NewInstance('mDatabase')->SetLabel('MySQL Database'),
|
||||
\RainLoop\Plugins\Property::NewInstance('mTable')->SetLabel('MySQL Table'),
|
||||
\RainLoop\Plugins\Property::NewInstance('mSql')->SetLabel('SQL statement')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT)
|
||||
->SetDescription('SQL statement (allowed wildcards :table, :email, :oldpass, :newpass, :domain, :username). Use SQL functions for encryption.')
|
||||
->SetDefaultValue('UPDATE :table SET password = md5(:newpass) WHERE domain = :domain AND username = :username and oldpass = md5(:oldpass)')
|
||||
);
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
class ChangePasswordCustomSqlPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
public function Init()
|
||||
{
|
||||
$this->addHook('main.fabrica', 'MainFabrica');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sName
|
||||
* @param mixed $oProvider
|
||||
*/
|
||||
public function MainFabrica($sName, &$oProvider)
|
||||
{
|
||||
switch ($sName)
|
||||
{
|
||||
case 'change-password':
|
||||
include_once __DIR__.'/ChangePasswordCustomSqlDriver.php';
|
||||
$oProvider = new ChangePasswordCustomSqlDriver();
|
||||
$oProvider
|
||||
->SetLogger($this->Manager()->Actions()->Logger())
|
||||
->SetmHost($this->Config()->Get('plugin', 'mHost', ''))
|
||||
->SetmUser($this->Config()->Get('plugin', 'mUser', ''))
|
||||
->SetmPass($this->Config()->Get('plugin', 'mPass', ''))
|
||||
->SetmDatabase($this->Config()->Get('plugin', 'mDatabase', ''))
|
||||
->SetmTable($this->Config()->Get('plugin', 'mTable', ''))
|
||||
->SetmSql($this->Config()->Get('plugin', 'mSql', ''))
|
||||
;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('mHost')->SetLabel('MySQL Host')
|
||||
->SetDefaultValue('127.0.0.1'),
|
||||
\RainLoop\Plugins\Property::NewInstance('mUser')->SetLabel('MySQL User'),
|
||||
\RainLoop\Plugins\Property::NewInstance('mPass')->SetLabel('MySQL Password')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD),
|
||||
\RainLoop\Plugins\Property::NewInstance('mDatabase')->SetLabel('MySQL Database'),
|
||||
\RainLoop\Plugins\Property::NewInstance('mTable')->SetLabel('MySQL Table'),
|
||||
\RainLoop\Plugins\Property::NewInstance('mSql')->SetLabel('SQL statement')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT)
|
||||
->SetDescription('SQL statement (allowed wildcards :table, :email, :oldpass, :newpass, :domain, :username). Use SQL functions for encryption.')
|
||||
->SetDefaultValue('UPDATE :table SET password = md5(:newpass) WHERE domain = :domain AND username = :username and oldpass = md5(:oldpass)')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,138 +1,138 @@
|
|||
<?php
|
||||
|
||||
class ChangePasswordCyberPanel implements \RainLoop\Providers\ChangePassword\ChangePasswordInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mHost = '127.0.0.1';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mUser = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mPass = '';
|
||||
|
||||
/**
|
||||
* @var \MailSo\Log\Logger
|
||||
*/
|
||||
private $oLogger = null;
|
||||
|
||||
/**
|
||||
* @param string $mHost
|
||||
*
|
||||
* @return \ChangePasswordCyberPanel
|
||||
*/
|
||||
public function SetmHost($mHost)
|
||||
{
|
||||
$this->mHost = $mHost;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mUser
|
||||
*
|
||||
* @return \ChangePasswordCyberPanel
|
||||
*/
|
||||
public function SetmUser($mUser)
|
||||
{
|
||||
$this->mUser = $mUser;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mPass
|
||||
*
|
||||
* @return \ChangePasswordCyberPanel
|
||||
*/
|
||||
public function SetmPass($mPass)
|
||||
{
|
||||
$this->mPass = $mPass;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \MailSo\Log\Logger $oLogger
|
||||
*
|
||||
* @return \ChangePasswordCyberPanel
|
||||
*/
|
||||
public function SetLogger($oLogger)
|
||||
{
|
||||
if ($oLogger instanceof \MailSo\Log\Logger)
|
||||
{
|
||||
$this->oLogger = $oLogger;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account $oAccount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function PasswordChangePossibility($oAccount)
|
||||
{
|
||||
return $oAccount && $oAccount->Email();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account $oAccount
|
||||
* @param string $sPrevPassword
|
||||
* @param string $sNewPassword
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ChangePassword(\RainLoop\Account $oAccount, $sPrevPassword, $sNewPassword)
|
||||
{
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->Write('Try to change password for '.$oAccount->Email());
|
||||
}
|
||||
|
||||
$bResult = false;
|
||||
$db = mysqli_connect($this->mHost, $this->mUser, $this->mPass, 'cyberpanel');
|
||||
|
||||
try
|
||||
{
|
||||
$sEmail = mysqli_real_escape_string($db, $oAccount->Email());
|
||||
$sEmailUser = mysqli_real_escape_string($db, \MailSo\Base\Utils::GetAccountNameFromEmail($sEmail));
|
||||
$sEmailDomain = mysqli_real_escape_string($db, \MailSo\Base\Utils::GetDomainFromEmail($sEmail));
|
||||
|
||||
$password_check_query = "SELECT * FROM e_users WHERE emailOwner_id = '$sEmailDomain' AND email = '$sEmail'";
|
||||
$result = mysqli_query($db, $password_check_query);
|
||||
$password_check = mysqli_fetch_assoc($result);
|
||||
|
||||
if (password_verify($sPrevPassword, substr($password_check['password'], 7))) {
|
||||
$hashed_password = mysqli_real_escape_string($db, '{CRYPT}'.password_hash($sNewPassword, PASSWORD_BCRYPT, ['cost' => 12,]));
|
||||
$password_update_query = "UPDATE e_users SET password = '$hashed_password' WHERE emailOwner_id = '$sEmailDomain' AND email = '$sEmail'";
|
||||
mysqli_query($db, $password_update_query);
|
||||
$bResult = true;
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->Write('Success! The password was changed.');
|
||||
}
|
||||
} else {
|
||||
$bResult = false;
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->Write('Something went wrong. Either the current password is incorrect or the new password does not meet the criteria.');
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (\Exception $oException)
|
||||
{
|
||||
$bResult = false;
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->WriteException($oException);
|
||||
}
|
||||
}
|
||||
|
||||
return $bResult;
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
class ChangePasswordCyberPanel implements \RainLoop\Providers\ChangePassword\ChangePasswordInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mHost = '127.0.0.1';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mUser = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mPass = '';
|
||||
|
||||
/**
|
||||
* @var \MailSo\Log\Logger
|
||||
*/
|
||||
private $oLogger = null;
|
||||
|
||||
/**
|
||||
* @param string $mHost
|
||||
*
|
||||
* @return \ChangePasswordCyberPanel
|
||||
*/
|
||||
public function SetmHost($mHost)
|
||||
{
|
||||
$this->mHost = $mHost;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mUser
|
||||
*
|
||||
* @return \ChangePasswordCyberPanel
|
||||
*/
|
||||
public function SetmUser($mUser)
|
||||
{
|
||||
$this->mUser = $mUser;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $mPass
|
||||
*
|
||||
* @return \ChangePasswordCyberPanel
|
||||
*/
|
||||
public function SetmPass($mPass)
|
||||
{
|
||||
$this->mPass = $mPass;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \MailSo\Log\Logger $oLogger
|
||||
*
|
||||
* @return \ChangePasswordCyberPanel
|
||||
*/
|
||||
public function SetLogger($oLogger)
|
||||
{
|
||||
if ($oLogger instanceof \MailSo\Log\Logger)
|
||||
{
|
||||
$this->oLogger = $oLogger;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account $oAccount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function PasswordChangePossibility($oAccount)
|
||||
{
|
||||
return $oAccount && $oAccount->Email();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account $oAccount
|
||||
* @param string $sPrevPassword
|
||||
* @param string $sNewPassword
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ChangePassword(\RainLoop\Account $oAccount, $sPrevPassword, $sNewPassword)
|
||||
{
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->Write('Try to change password for '.$oAccount->Email());
|
||||
}
|
||||
|
||||
$bResult = false;
|
||||
$db = mysqli_connect($this->mHost, $this->mUser, $this->mPass, 'cyberpanel');
|
||||
|
||||
try
|
||||
{
|
||||
$sEmail = mysqli_real_escape_string($db, $oAccount->Email());
|
||||
$sEmailUser = mysqli_real_escape_string($db, \MailSo\Base\Utils::GetAccountNameFromEmail($sEmail));
|
||||
$sEmailDomain = mysqli_real_escape_string($db, \MailSo\Base\Utils::GetDomainFromEmail($sEmail));
|
||||
|
||||
$password_check_query = "SELECT * FROM e_users WHERE emailOwner_id = '$sEmailDomain' AND email = '$sEmail'";
|
||||
$result = mysqli_query($db, $password_check_query);
|
||||
$password_check = mysqli_fetch_assoc($result);
|
||||
|
||||
if (password_verify($sPrevPassword, substr($password_check['password'], 7))) {
|
||||
$hashed_password = mysqli_real_escape_string($db, '{CRYPT}'.password_hash($sNewPassword, PASSWORD_BCRYPT, ['cost' => 12,]));
|
||||
$password_update_query = "UPDATE e_users SET password = '$hashed_password' WHERE emailOwner_id = '$sEmailDomain' AND email = '$sEmail'";
|
||||
mysqli_query($db, $password_update_query);
|
||||
$bResult = true;
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->Write('Success! The password was changed.');
|
||||
}
|
||||
} else {
|
||||
$bResult = false;
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->Write('Something went wrong. Either the current password is incorrect or the new password does not meet the criteria.');
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (\Exception $oException)
|
||||
{
|
||||
$bResult = false;
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->WriteException($oException);
|
||||
}
|
||||
}
|
||||
|
||||
return $bResult;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,44 +1,44 @@
|
|||
<?php
|
||||
|
||||
class ChangePasswordCyberPanelPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
public function Init()
|
||||
{
|
||||
$this->addHook('main.fabrica', 'MainFabrica');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sName
|
||||
* @param mixed $oProvider
|
||||
*/
|
||||
public function MainFabrica($sName, &$oProvider)
|
||||
{
|
||||
switch ($sName)
|
||||
{
|
||||
case 'change-password':
|
||||
include_once __DIR__.'/ChangePasswordCyberPanel.php';
|
||||
$oProvider = new ChangePasswordCyberPanel();
|
||||
$oProvider
|
||||
->SetLogger($this->Manager()->Actions()->Logger())
|
||||
->SetmHost($this->Config()->Get('plugin', 'mHost', ''))
|
||||
->SetmUser($this->Config()->Get('plugin', 'mUser', ''))
|
||||
->SetmPass($this->Config()->Get('plugin', 'mPass', ''))
|
||||
;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('mHost')->SetLabel('MySQL Host')
|
||||
->SetDefaultValue('127.0.0.1'),
|
||||
\RainLoop\Plugins\Property::NewInstance('mUser')->SetLabel('MySQL User'),
|
||||
\RainLoop\Plugins\Property::NewInstance('mPass')->SetLabel('MySQL Password')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD)
|
||||
);
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
class ChangePasswordCyberPanelPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
public function Init()
|
||||
{
|
||||
$this->addHook('main.fabrica', 'MainFabrica');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sName
|
||||
* @param mixed $oProvider
|
||||
*/
|
||||
public function MainFabrica($sName, &$oProvider)
|
||||
{
|
||||
switch ($sName)
|
||||
{
|
||||
case 'change-password':
|
||||
include_once __DIR__.'/ChangePasswordCyberPanel.php';
|
||||
$oProvider = new ChangePasswordCyberPanel();
|
||||
$oProvider
|
||||
->SetLogger($this->Manager()->Actions()->Logger())
|
||||
->SetmHost($this->Config()->Get('plugin', 'mHost', ''))
|
||||
->SetmUser($this->Config()->Get('plugin', 'mUser', ''))
|
||||
->SetmPass($this->Config()->Get('plugin', 'mPass', ''))
|
||||
;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('mHost')->SetLabel('MySQL Host')
|
||||
->SetDefaultValue('127.0.0.1'),
|
||||
\RainLoop\Plugins\Property::NewInstance('mUser')->SetLabel('MySQL User'),
|
||||
\RainLoop\Plugins\Property::NewInstance('mPass')->SetLabel('MySQL Password')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ class DirectAdminChangePasswordDriver implements \RainLoop\Providers\ChangePassw
|
|||
* @var string
|
||||
*/
|
||||
private $iPort = 2222;
|
||||
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
@ -21,7 +21,7 @@ class DirectAdminChangePasswordDriver implements \RainLoop\Providers\ChangePassw
|
|||
* @var \MailSo\Log\Logger
|
||||
*/
|
||||
private $oLogger = null;
|
||||
|
||||
|
||||
/**
|
||||
* @param string $sHost
|
||||
* @param int $iPort
|
||||
|
@ -97,7 +97,7 @@ class DirectAdminChangePasswordDriver implements \RainLoop\Providers\ChangePassw
|
|||
$sHost = \str_replace('{user:host-smtp}', $oAccount->Domain()->OutHost(), $sHost);
|
||||
$sHost = \str_replace('{user:domain}', \MailSo\Base\Utils::GetDomainFromEmail($sEmail), $sHost);
|
||||
$sHost = \rtrim($this->sHost, '/\\');
|
||||
|
||||
|
||||
if (!\preg_match('/^http[s]?:\/\//i', $sHost))
|
||||
{
|
||||
$sHost = 'http://'.$sHost;
|
||||
|
|
|
@ -1,76 +1,76 @@
|
|||
<?php
|
||||
|
||||
class FroxlorchangePasswordPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
public function Init()
|
||||
{
|
||||
$this->addHook('main.fabrica', 'MainFabrica');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function Supported()
|
||||
{
|
||||
if (!extension_loaded('pdo') || !class_exists('PDO'))
|
||||
{
|
||||
return 'The PHP exention PDO (mysql) must be installed to use this plugin';
|
||||
}
|
||||
|
||||
$aDrivers = \PDO::getAvailableDrivers();
|
||||
if (!is_array($aDrivers) || !in_array('mysql', $aDrivers))
|
||||
{
|
||||
return 'The PHP exention PDO (mysql) must be installed to use this plugin';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sName
|
||||
* @param mixed $oProvider
|
||||
*/
|
||||
public function MainFabrica($sName, &$oProvider)
|
||||
{
|
||||
switch ($sName)
|
||||
{
|
||||
case 'change-password':
|
||||
|
||||
$sDsn = \trim($this->Config()->Get('plugin', 'pdo_dsn', ''));
|
||||
$sUser = (string) $this->Config()->Get('plugin', 'user', '');
|
||||
$sPassword = (string) $this->Config()->Get('plugin', 'password', '');
|
||||
|
||||
if (!empty($sDsn) && 0 < \strlen($sUser) && 0 < \strlen($sPassword))
|
||||
{
|
||||
include_once __DIR__.'/FroxlorChangePasswordDriver.php';
|
||||
|
||||
$oProvider = new FroxlorChangePasswordDriver();
|
||||
$oProvider->SetLogger($this->Manager()->Actions()->Logger());
|
||||
$oProvider->SetConfig($sDsn, $sUser, $sPassword);
|
||||
$oProvider->SetAllowedEmails(\strtolower(\trim($this->Config()->Get('plugin', 'allowed_emails', ''))));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('pdo_dsn')->SetLabel('Froxlor PDO dsn')
|
||||
->SetDefaultValue('mysql:host=127.0.0.1;dbname=froxlor'),
|
||||
\RainLoop\Plugins\Property::NewInstance('user')->SetLabel('DB User')
|
||||
->SetDefaultValue('root'),
|
||||
\RainLoop\Plugins\Property::NewInstance('password')->SetLabel('DB Password')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD)
|
||||
->SetDefaultValue(''),
|
||||
\RainLoop\Plugins\Property::NewInstance('allowed_emails')->SetLabel('Allowed emails')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT)
|
||||
->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@domain1.net user2@domain1.net *@domain2.net')
|
||||
->SetDefaultValue('*')
|
||||
);
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
class FroxlorchangePasswordPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
public function Init()
|
||||
{
|
||||
$this->addHook('main.fabrica', 'MainFabrica');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function Supported()
|
||||
{
|
||||
if (!extension_loaded('pdo') || !class_exists('PDO'))
|
||||
{
|
||||
return 'The PHP exention PDO (mysql) must be installed to use this plugin';
|
||||
}
|
||||
|
||||
$aDrivers = \PDO::getAvailableDrivers();
|
||||
if (!is_array($aDrivers) || !in_array('mysql', $aDrivers))
|
||||
{
|
||||
return 'The PHP exention PDO (mysql) must be installed to use this plugin';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sName
|
||||
* @param mixed $oProvider
|
||||
*/
|
||||
public function MainFabrica($sName, &$oProvider)
|
||||
{
|
||||
switch ($sName)
|
||||
{
|
||||
case 'change-password':
|
||||
|
||||
$sDsn = \trim($this->Config()->Get('plugin', 'pdo_dsn', ''));
|
||||
$sUser = (string) $this->Config()->Get('plugin', 'user', '');
|
||||
$sPassword = (string) $this->Config()->Get('plugin', 'password', '');
|
||||
|
||||
if (!empty($sDsn) && 0 < \strlen($sUser) && 0 < \strlen($sPassword))
|
||||
{
|
||||
include_once __DIR__.'/FroxlorChangePasswordDriver.php';
|
||||
|
||||
$oProvider = new FroxlorChangePasswordDriver();
|
||||
$oProvider->SetLogger($this->Manager()->Actions()->Logger());
|
||||
$oProvider->SetConfig($sDsn, $sUser, $sPassword);
|
||||
$oProvider->SetAllowedEmails(\strtolower(\trim($this->Config()->Get('plugin', 'allowed_emails', ''))));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('pdo_dsn')->SetLabel('Froxlor PDO dsn')
|
||||
->SetDefaultValue('mysql:host=127.0.0.1;dbname=froxlor'),
|
||||
\RainLoop\Plugins\Property::NewInstance('user')->SetLabel('DB User')
|
||||
->SetDefaultValue('root'),
|
||||
\RainLoop\Plugins\Property::NewInstance('password')->SetLabel('DB Password')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD)
|
||||
->SetDefaultValue(''),
|
||||
\RainLoop\Plugins\Property::NewInstance('allowed_emails')->SetLabel('Allowed emails')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT)
|
||||
->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@domain1.net user2@domain1.net *@domain2.net')
|
||||
->SetDefaultValue('*')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +1,49 @@
|
|||
<?php
|
||||
|
||||
class GoogleAnalyticsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function Init()
|
||||
{
|
||||
if ('' !== $this->Config()->Get('plugin', 'account', ''))
|
||||
{
|
||||
$this->addJs('js/include.js');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
$oAccount = \RainLoop\Plugins\Property::NewInstance('account')->SetLabel('Account')
|
||||
->SetAllowedInJs(true)
|
||||
->SetDefaultValue('')
|
||||
;
|
||||
|
||||
if (\method_exists($oAccount, 'SetPlaceholder'))
|
||||
{
|
||||
$oAccount->SetPlaceholder('UA-XXXXXXXX-X');
|
||||
}
|
||||
|
||||
return array($oAccount,
|
||||
\RainLoop\Plugins\Property::NewInstance('domain_name')->SetLabel('Domain Name')
|
||||
->SetAllowedInJs(true)
|
||||
->SetDefaultValue(''),
|
||||
\RainLoop\Plugins\Property::NewInstance('universal_analytics')->SetLabel('Use Universal Analytics')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL)
|
||||
->SetAllowedInJs(true)
|
||||
->SetDefaultValue(true),
|
||||
\RainLoop\Plugins\Property::NewInstance('track_pageview')->SetLabel('Track Pageview')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL)
|
||||
->SetAllowedInJs(true)
|
||||
->SetDefaultValue(true),
|
||||
\RainLoop\Plugins\Property::NewInstance('send_events')->SetLabel('Send Events')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL)
|
||||
->SetAllowedInJs(true)
|
||||
->SetDefaultValue(false)
|
||||
);
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
class GoogleAnalyticsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function Init()
|
||||
{
|
||||
if ('' !== $this->Config()->Get('plugin', 'account', ''))
|
||||
{
|
||||
$this->addJs('js/include.js');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
$oAccount = \RainLoop\Plugins\Property::NewInstance('account')->SetLabel('Account')
|
||||
->SetAllowedInJs(true)
|
||||
->SetDefaultValue('')
|
||||
;
|
||||
|
||||
if (\method_exists($oAccount, 'SetPlaceholder'))
|
||||
{
|
||||
$oAccount->SetPlaceholder('UA-XXXXXXXX-X');
|
||||
}
|
||||
|
||||
return array($oAccount,
|
||||
\RainLoop\Plugins\Property::NewInstance('domain_name')->SetLabel('Domain Name')
|
||||
->SetAllowedInJs(true)
|
||||
->SetDefaultValue(''),
|
||||
\RainLoop\Plugins\Property::NewInstance('universal_analytics')->SetLabel('Use Universal Analytics')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL)
|
||||
->SetAllowedInJs(true)
|
||||
->SetDefaultValue(true),
|
||||
\RainLoop\Plugins\Property::NewInstance('track_pageview')->SetLabel('Track Pageview')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL)
|
||||
->SetAllowedInJs(true)
|
||||
->SetDefaultValue(true),
|
||||
\RainLoop\Plugins\Property::NewInstance('send_events')->SetLabel('Send Events')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::BOOL)
|
||||
->SetAllowedInJs(true)
|
||||
->SetDefaultValue(false)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,95 +1,95 @@
|
|||
<?php
|
||||
|
||||
class IspmailChangePasswordPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
public function Init()
|
||||
{
|
||||
$this->addHook('main.fabrica', 'MainFabrica');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function Supported()
|
||||
{
|
||||
if (!extension_loaded('pdo') || !class_exists('PDO'))
|
||||
{
|
||||
return 'The PHP extension PDO (mysql) must be installed to use this plugin';
|
||||
}
|
||||
|
||||
$aDrivers = \PDO::getAvailableDrivers();
|
||||
if (!is_array($aDrivers) || !in_array('mysql', $aDrivers))
|
||||
{
|
||||
return 'The PHP extension PDO (mysql) must be installed to use this plugin';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sName
|
||||
* @param mixed $oProvider
|
||||
*/
|
||||
public function MainFabrica($sName, &$oProvider)
|
||||
{
|
||||
switch ($sName)
|
||||
{
|
||||
case 'change-password':
|
||||
|
||||
include_once __DIR__.'/ChangePasswordISPmailDriver.php';
|
||||
|
||||
$oProvider = new ChangePasswordISPmailDriver();
|
||||
|
||||
$oProvider
|
||||
->SetHost($this->Config()->Get('plugin', 'host', ''))
|
||||
->SetPort((int) $this->Config()->Get('plugin', 'port', 3306))
|
||||
->SetDatabase($this->Config()->Get('plugin', 'database', ''))
|
||||
->SetTable($this->Config()->Get('plugin', 'table', ''))
|
||||
->SetUserColumn($this->Config()->Get('plugin', 'usercol', ''))
|
||||
->SetPasswordColumn($this->Config()->Get('plugin', 'passcol', ''))
|
||||
->SetUser($this->Config()->Get('plugin', 'user', ''))
|
||||
->SetPassword($this->Config()->Get('plugin', 'password', ''))
|
||||
->SetEncrypt($this->Config()->Get('plugin', 'encrypt', ''))
|
||||
->SetAllowedEmails(\strtolower(\trim($this->Config()->Get('plugin', 'allowed_emails', ''))))
|
||||
->SetLogger($this->Manager()->Actions()->Logger())
|
||||
;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('host')->SetLabel('MySQL Host')
|
||||
->SetDefaultValue('127.0.0.1'),
|
||||
\RainLoop\Plugins\Property::NewInstance('port')->SetLabel('MySQL Port')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::INT)
|
||||
->SetDefaultValue(3306),
|
||||
\RainLoop\Plugins\Property::NewInstance('database')->SetLabel('MySQL Database')
|
||||
->SetDefaultValue('mailserver'),
|
||||
\RainLoop\Plugins\Property::NewInstance('table')->SetLabel('MySQL table')
|
||||
->SetDefaultValue('virtual_users'),
|
||||
\RainLoop\Plugins\Property::NewInstance('usercol')->SetLabel('MySQL username column')
|
||||
->SetDefaultValue('email'),
|
||||
\RainLoop\Plugins\Property::NewInstance('passcol')->SetLabel('MySQL password column')
|
||||
->SetDefaultValue('password'),
|
||||
\RainLoop\Plugins\Property::NewInstance('user')->SetLabel('MySQL User')
|
||||
->SetDefaultValue('mailuser'),
|
||||
\RainLoop\Plugins\Property::NewInstance('password')->SetLabel('MySQL Password')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD)
|
||||
->SetDefaultValue(''),
|
||||
\RainLoop\Plugins\Property::NewInstance('encrypt')->SetLabel('Encrypt')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION)
|
||||
->SetDefaultValue(array('PLAIN-MD5', 'SHA256-CRYPT'))
|
||||
->SetDescription('In what way do you want the passwords to be crypted ?'),
|
||||
\RainLoop\Plugins\Property::NewInstance('allowed_emails')->SetLabel('Allowed emails')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT)
|
||||
->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@domain1.net user2@domain1.net *@domain2.net')
|
||||
->SetDefaultValue('*')
|
||||
);
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
class IspmailChangePasswordPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
public function Init()
|
||||
{
|
||||
$this->addHook('main.fabrica', 'MainFabrica');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function Supported()
|
||||
{
|
||||
if (!extension_loaded('pdo') || !class_exists('PDO'))
|
||||
{
|
||||
return 'The PHP extension PDO (mysql) must be installed to use this plugin';
|
||||
}
|
||||
|
||||
$aDrivers = \PDO::getAvailableDrivers();
|
||||
if (!is_array($aDrivers) || !in_array('mysql', $aDrivers))
|
||||
{
|
||||
return 'The PHP extension PDO (mysql) must be installed to use this plugin';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sName
|
||||
* @param mixed $oProvider
|
||||
*/
|
||||
public function MainFabrica($sName, &$oProvider)
|
||||
{
|
||||
switch ($sName)
|
||||
{
|
||||
case 'change-password':
|
||||
|
||||
include_once __DIR__.'/ChangePasswordISPmailDriver.php';
|
||||
|
||||
$oProvider = new ChangePasswordISPmailDriver();
|
||||
|
||||
$oProvider
|
||||
->SetHost($this->Config()->Get('plugin', 'host', ''))
|
||||
->SetPort((int) $this->Config()->Get('plugin', 'port', 3306))
|
||||
->SetDatabase($this->Config()->Get('plugin', 'database', ''))
|
||||
->SetTable($this->Config()->Get('plugin', 'table', ''))
|
||||
->SetUserColumn($this->Config()->Get('plugin', 'usercol', ''))
|
||||
->SetPasswordColumn($this->Config()->Get('plugin', 'passcol', ''))
|
||||
->SetUser($this->Config()->Get('plugin', 'user', ''))
|
||||
->SetPassword($this->Config()->Get('plugin', 'password', ''))
|
||||
->SetEncrypt($this->Config()->Get('plugin', 'encrypt', ''))
|
||||
->SetAllowedEmails(\strtolower(\trim($this->Config()->Get('plugin', 'allowed_emails', ''))))
|
||||
->SetLogger($this->Manager()->Actions()->Logger())
|
||||
;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('host')->SetLabel('MySQL Host')
|
||||
->SetDefaultValue('127.0.0.1'),
|
||||
\RainLoop\Plugins\Property::NewInstance('port')->SetLabel('MySQL Port')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::INT)
|
||||
->SetDefaultValue(3306),
|
||||
\RainLoop\Plugins\Property::NewInstance('database')->SetLabel('MySQL Database')
|
||||
->SetDefaultValue('mailserver'),
|
||||
\RainLoop\Plugins\Property::NewInstance('table')->SetLabel('MySQL table')
|
||||
->SetDefaultValue('virtual_users'),
|
||||
\RainLoop\Plugins\Property::NewInstance('usercol')->SetLabel('MySQL username column')
|
||||
->SetDefaultValue('email'),
|
||||
\RainLoop\Plugins\Property::NewInstance('passcol')->SetLabel('MySQL password column')
|
||||
->SetDefaultValue('password'),
|
||||
\RainLoop\Plugins\Property::NewInstance('user')->SetLabel('MySQL User')
|
||||
->SetDefaultValue('mailuser'),
|
||||
\RainLoop\Plugins\Property::NewInstance('password')->SetLabel('MySQL Password')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD)
|
||||
->SetDefaultValue(''),
|
||||
\RainLoop\Plugins\Property::NewInstance('encrypt')->SetLabel('Encrypt')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION)
|
||||
->SetDefaultValue(array('PLAIN-MD5', 'SHA256-CRYPT'))
|
||||
->SetDescription('In what way do you want the passwords to be crypted ?'),
|
||||
\RainLoop\Plugins\Property::NewInstance('allowed_emails')->SetLabel('Allowed emails')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT)
|
||||
->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@domain1.net user2@domain1.net *@domain2.net')
|
||||
->SetDefaultValue('*')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,162 +1,162 @@
|
|||
<?php
|
||||
|
||||
class MailcowChangePasswordDriver implements \RainLoop\Providers\ChangePassword\ChangePasswordInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sDsn = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sUser = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sPassword = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sAllowedEmails = '';
|
||||
|
||||
/**
|
||||
* @var \MailSo\Log\Logger
|
||||
*/
|
||||
private $oLogger = null;
|
||||
|
||||
/**
|
||||
* @param string $sDsn
|
||||
* @param string $sUser
|
||||
* @param string $sPassword
|
||||
*
|
||||
* @return \IspConfigChangePasswordDriver
|
||||
*/
|
||||
public function SetConfig($sDsn, $sUser, $sPassword)
|
||||
{
|
||||
$this->sDsn = $sDsn;
|
||||
$this->sUser = $sUser;
|
||||
$this->sPassword = $sPassword;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sAllowedEmails
|
||||
*
|
||||
* @return \IspConfigChangePasswordDriver
|
||||
*/
|
||||
public function SetAllowedEmails($sAllowedEmails)
|
||||
{
|
||||
$this->sAllowedEmails = $sAllowedEmails;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \MailSo\Log\Logger $oLogger
|
||||
*
|
||||
* @return \IspConfigChangePasswordDriver
|
||||
*/
|
||||
public function SetLogger($oLogger)
|
||||
{
|
||||
if ($oLogger instanceof \MailSo\Log\Logger)
|
||||
{
|
||||
$this->oLogger = $oLogger;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account $oAccount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function PasswordChangePossibility($oAccount)
|
||||
{
|
||||
return $oAccount && $oAccount->Email() &&
|
||||
\RainLoop\Plugins\Helper::ValidateWildcardValues($oAccount->Email(), $this->sAllowedEmails);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account $oAccount
|
||||
* @param string $sPrevPassword
|
||||
* @param string $sNewPassword
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ChangePassword(\RainLoop\Account $oAccount, $sPrevPassword, $sNewPassword)
|
||||
{
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->Write('Mailcow: Try to change password for '.$oAccount->Email());
|
||||
}
|
||||
|
||||
$bResult = false;
|
||||
if (!empty($this->sDsn) && 0 < \strlen($this->sUser) && 0 < \strlen($this->sPassword) && $oAccount)
|
||||
{
|
||||
try
|
||||
{
|
||||
$oPdo = new \PDO($this->sDsn, $this->sUser, $this->sPassword);
|
||||
$oPdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$oStmt = $oPdo->prepare('SELECT password, username FROM mailbox WHERE username = ? LIMIT 1');
|
||||
if ($oStmt->execute(array($oAccount->IncLogin())))
|
||||
{
|
||||
$aFetchResult = $oStmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
if (\is_array($aFetchResult) && isset($aFetchResult[0]['password'], $aFetchResult[0]['username']))
|
||||
{
|
||||
$sDbPassword = $aFetchResult[0]['password'];
|
||||
if (\substr($sDbPassword, 0, 14) === '{SHA512-CRYPT}') {
|
||||
$sDbSalt = \substr($sDbPassword, 17, 16);
|
||||
} else {
|
||||
$sDbSalt = \substr($sDbPassword, 3, 16);
|
||||
}
|
||||
|
||||
if ('{SHA512-CRYPT}'.\crypt($sPrevPassword, '$6$'.$sDbSalt) === $sDbPassword)
|
||||
{
|
||||
$oStmt = $oPdo->prepare('UPDATE mailbox SET password = ? WHERE username = ?');
|
||||
if ($oStmt->execute(array($this->cryptPassword($sNewPassword), $aFetchResult[0]['username']))) {
|
||||
$oStmt = $oPdo ->prepare('UPDATE users SET digesta1=MD5(CONCAT(?, ":SabreDAV:", ?)) WHERE username=?');
|
||||
if ($oStmt->execute(array($aFetchResult[0]['username'],$sNewPassword,$aFetchResult[0]['username']))) {
|
||||
//the MailCow & SabreDav have been updated, now update the doveadm password
|
||||
exec("/usr/bin/doveadm pw -s SHA512-CRYPT -p $sNewPassword", $hash, $return);
|
||||
$bResult = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (\Exception $oException)
|
||||
{
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->WriteException($oException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $bResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sPassword
|
||||
* @return string
|
||||
*/
|
||||
private function cryptPassword($sPassword)
|
||||
{
|
||||
$sSalt = '';
|
||||
$sBase64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
|
||||
for ($iIndex = 0; $iIndex < 16; $iIndex++)
|
||||
{
|
||||
$sSalt .= $sBase64[\rand(0, 63)];
|
||||
}
|
||||
|
||||
$crypted = \crypt($sPassword, '$6$'.$sSalt);
|
||||
return '{SHA512-CRYPT}'.$crypted;
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
class MailcowChangePasswordDriver implements \RainLoop\Providers\ChangePassword\ChangePasswordInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sDsn = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sUser = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sPassword = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sAllowedEmails = '';
|
||||
|
||||
/**
|
||||
* @var \MailSo\Log\Logger
|
||||
*/
|
||||
private $oLogger = null;
|
||||
|
||||
/**
|
||||
* @param string $sDsn
|
||||
* @param string $sUser
|
||||
* @param string $sPassword
|
||||
*
|
||||
* @return \IspConfigChangePasswordDriver
|
||||
*/
|
||||
public function SetConfig($sDsn, $sUser, $sPassword)
|
||||
{
|
||||
$this->sDsn = $sDsn;
|
||||
$this->sUser = $sUser;
|
||||
$this->sPassword = $sPassword;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sAllowedEmails
|
||||
*
|
||||
* @return \IspConfigChangePasswordDriver
|
||||
*/
|
||||
public function SetAllowedEmails($sAllowedEmails)
|
||||
{
|
||||
$this->sAllowedEmails = $sAllowedEmails;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \MailSo\Log\Logger $oLogger
|
||||
*
|
||||
* @return \IspConfigChangePasswordDriver
|
||||
*/
|
||||
public function SetLogger($oLogger)
|
||||
{
|
||||
if ($oLogger instanceof \MailSo\Log\Logger)
|
||||
{
|
||||
$this->oLogger = $oLogger;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account $oAccount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function PasswordChangePossibility($oAccount)
|
||||
{
|
||||
return $oAccount && $oAccount->Email() &&
|
||||
\RainLoop\Plugins\Helper::ValidateWildcardValues($oAccount->Email(), $this->sAllowedEmails);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Account $oAccount
|
||||
* @param string $sPrevPassword
|
||||
* @param string $sNewPassword
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ChangePassword(\RainLoop\Account $oAccount, $sPrevPassword, $sNewPassword)
|
||||
{
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->Write('Mailcow: Try to change password for '.$oAccount->Email());
|
||||
}
|
||||
|
||||
$bResult = false;
|
||||
if (!empty($this->sDsn) && 0 < \strlen($this->sUser) && 0 < \strlen($this->sPassword) && $oAccount)
|
||||
{
|
||||
try
|
||||
{
|
||||
$oPdo = new \PDO($this->sDsn, $this->sUser, $this->sPassword);
|
||||
$oPdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$oStmt = $oPdo->prepare('SELECT password, username FROM mailbox WHERE username = ? LIMIT 1');
|
||||
if ($oStmt->execute(array($oAccount->IncLogin())))
|
||||
{
|
||||
$aFetchResult = $oStmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
if (\is_array($aFetchResult) && isset($aFetchResult[0]['password'], $aFetchResult[0]['username']))
|
||||
{
|
||||
$sDbPassword = $aFetchResult[0]['password'];
|
||||
if (\substr($sDbPassword, 0, 14) === '{SHA512-CRYPT}') {
|
||||
$sDbSalt = \substr($sDbPassword, 17, 16);
|
||||
} else {
|
||||
$sDbSalt = \substr($sDbPassword, 3, 16);
|
||||
}
|
||||
|
||||
if ('{SHA512-CRYPT}'.\crypt($sPrevPassword, '$6$'.$sDbSalt) === $sDbPassword)
|
||||
{
|
||||
$oStmt = $oPdo->prepare('UPDATE mailbox SET password = ? WHERE username = ?');
|
||||
if ($oStmt->execute(array($this->cryptPassword($sNewPassword), $aFetchResult[0]['username']))) {
|
||||
$oStmt = $oPdo ->prepare('UPDATE users SET digesta1=MD5(CONCAT(?, ":SabreDAV:", ?)) WHERE username=?');
|
||||
if ($oStmt->execute(array($aFetchResult[0]['username'],$sNewPassword,$aFetchResult[0]['username']))) {
|
||||
//the MailCow & SabreDav have been updated, now update the doveadm password
|
||||
exec("/usr/bin/doveadm pw -s SHA512-CRYPT -p $sNewPassword", $hash, $return);
|
||||
$bResult = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (\Exception $oException)
|
||||
{
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$this->oLogger->WriteException($oException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $bResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sPassword
|
||||
* @return string
|
||||
*/
|
||||
private function cryptPassword($sPassword)
|
||||
{
|
||||
$sSalt = '';
|
||||
$sBase64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
|
||||
for ($iIndex = 0; $iIndex < 16; $iIndex++)
|
||||
{
|
||||
$sSalt .= $sBase64[\rand(0, 63)];
|
||||
}
|
||||
|
||||
$crypted = \crypt($sPassword, '$6$'.$sSalt);
|
||||
return '{SHA512-CRYPT}'.$crypted;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,76 +1,76 @@
|
|||
<?php
|
||||
|
||||
class MailcowChangePasswordPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
public function Init()
|
||||
{
|
||||
$this->addHook('main.fabrica', 'MainFabrica');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function Supported()
|
||||
{
|
||||
if (!extension_loaded('pdo') || !class_exists('PDO'))
|
||||
{
|
||||
return 'The PHP extension PDO (mysql) must be installed to use this plugin';
|
||||
}
|
||||
|
||||
$aDrivers = \PDO::getAvailableDrivers();
|
||||
if (!is_array($aDrivers) || !in_array('mysql', $aDrivers))
|
||||
{
|
||||
return 'The PHP extension PDO (mysql) must be installed to use this plugin';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sName
|
||||
* @param mixed $oProvider
|
||||
*/
|
||||
public function MainFabrica($sName, &$oProvider)
|
||||
{
|
||||
switch ($sName)
|
||||
{
|
||||
case 'change-password':
|
||||
|
||||
$sDsn = \trim($this->Config()->Get('plugin', 'pdo_dsn', ''));
|
||||
$sUser = (string) $this->Config()->Get('plugin', 'user', '');
|
||||
$sPassword = (string) $this->Config()->Get('plugin', 'password', '');
|
||||
|
||||
if (!empty($sDsn) && 0 < \strlen($sUser) && 0 < \strlen($sPassword))
|
||||
{
|
||||
include_once __DIR__.'/MailcowChangePasswordDriver.php';
|
||||
|
||||
$oProvider = new MailcowChangePasswordDriver();
|
||||
$oProvider->SetLogger($this->Manager()->Actions()->Logger());
|
||||
$oProvider->SetConfig($sDsn, $sUser, $sPassword);
|
||||
$oProvider->SetAllowedEmails(\strtolower(\trim($this->Config()->Get('plugin', 'allowed_emails', ''))));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('pdo_dsn')->SetLabel('Mailcow PDO dsn')
|
||||
->SetDefaultValue('mysql:host=127.0.0.1;dbname=mailcow'),
|
||||
\RainLoop\Plugins\Property::NewInstance('user')->SetLabel('DB User')
|
||||
->SetDefaultValue('mailcow'),
|
||||
\RainLoop\Plugins\Property::NewInstance('password')->SetLabel('DB Password')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD)
|
||||
->SetDefaultValue(''),
|
||||
\RainLoop\Plugins\Property::NewInstance('allowed_emails')->SetLabel('Allowed emails')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT)
|
||||
->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@domain1.net user2@domain1.net *@domain2.net')
|
||||
->SetDefaultValue('*')
|
||||
);
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
class MailcowChangePasswordPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
public function Init()
|
||||
{
|
||||
$this->addHook('main.fabrica', 'MainFabrica');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function Supported()
|
||||
{
|
||||
if (!extension_loaded('pdo') || !class_exists('PDO'))
|
||||
{
|
||||
return 'The PHP extension PDO (mysql) must be installed to use this plugin';
|
||||
}
|
||||
|
||||
$aDrivers = \PDO::getAvailableDrivers();
|
||||
if (!is_array($aDrivers) || !in_array('mysql', $aDrivers))
|
||||
{
|
||||
return 'The PHP extension PDO (mysql) must be installed to use this plugin';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sName
|
||||
* @param mixed $oProvider
|
||||
*/
|
||||
public function MainFabrica($sName, &$oProvider)
|
||||
{
|
||||
switch ($sName)
|
||||
{
|
||||
case 'change-password':
|
||||
|
||||
$sDsn = \trim($this->Config()->Get('plugin', 'pdo_dsn', ''));
|
||||
$sUser = (string) $this->Config()->Get('plugin', 'user', '');
|
||||
$sPassword = (string) $this->Config()->Get('plugin', 'password', '');
|
||||
|
||||
if (!empty($sDsn) && 0 < \strlen($sUser) && 0 < \strlen($sPassword))
|
||||
{
|
||||
include_once __DIR__.'/MailcowChangePasswordDriver.php';
|
||||
|
||||
$oProvider = new MailcowChangePasswordDriver();
|
||||
$oProvider->SetLogger($this->Manager()->Actions()->Logger());
|
||||
$oProvider->SetConfig($sDsn, $sUser, $sPassword);
|
||||
$oProvider->SetAllowedEmails(\strtolower(\trim($this->Config()->Get('plugin', 'allowed_emails', ''))));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('pdo_dsn')->SetLabel('Mailcow PDO dsn')
|
||||
->SetDefaultValue('mysql:host=127.0.0.1;dbname=mailcow'),
|
||||
\RainLoop\Plugins\Property::NewInstance('user')->SetLabel('DB User')
|
||||
->SetDefaultValue('mailcow'),
|
||||
\RainLoop\Plugins\Property::NewInstance('password')->SetLabel('DB Password')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD)
|
||||
->SetDefaultValue(''),
|
||||
\RainLoop\Plugins\Property::NewInstance('allowed_emails')->SetLabel('Allowed emails')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT)
|
||||
->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@domain1.net user2@domain1.net *@domain2.net')
|
||||
->SetDefaultValue('*')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -289,7 +289,7 @@ class ChangePasswordPostfixAdminDriver implements \RainLoop\Providers\ChangePass
|
|||
if (function_exists('random_bytes')) {
|
||||
$sSalt = substr(base64_encode(random_bytes(32)), 0, 16);
|
||||
} else {
|
||||
$sSalt = substr(str_shuffle('./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'), 0, 16);
|
||||
$sSalt = substr(str_shuffle('./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'), 0, 16);
|
||||
}
|
||||
switch (strtolower($this->sEncrypt))
|
||||
{
|
||||
|
|
|
@ -1,100 +1,100 @@
|
|||
<?php
|
||||
|
||||
class PostfixadminChangePasswordPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
public function Init()
|
||||
{
|
||||
$this->addHook('main.fabrica', 'MainFabrica');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function Supported()
|
||||
{
|
||||
if (!extension_loaded('pdo') || !class_exists('PDO'))
|
||||
{
|
||||
return 'The PHP extension PDO must be installed to use this plugin';
|
||||
}
|
||||
|
||||
$aDrivers = \PDO::getAvailableDrivers();
|
||||
if (!is_array($aDrivers) || (!in_array('mysql', $aDrivers) && !in_array('pgsql', $aDrivers)))
|
||||
{
|
||||
return 'The PHP extension PDO (mysql or pgsql) must be installed to use this plugin';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sName
|
||||
* @param mixed $oProvider
|
||||
*/
|
||||
public function MainFabrica($sName, &$oProvider)
|
||||
{
|
||||
switch ($sName)
|
||||
{
|
||||
case 'change-password':
|
||||
|
||||
include_once __DIR__.'/ChangePasswordPostfixAdminDriver.php';
|
||||
|
||||
$oProvider = new ChangePasswordPostfixAdminDriver();
|
||||
|
||||
$oProvider
|
||||
->SetEngine($this->Config()->Get('plugin', 'engine',''))
|
||||
->SetHost($this->Config()->Get('plugin', 'host', ''))
|
||||
->SetPort((int) $this->Config()->Get('plugin', 'port', 3306))
|
||||
->SetDatabase($this->Config()->Get('plugin', 'database', ''))
|
||||
->SetTable($this->Config()->Get('plugin', 'table', ''))
|
||||
->SetUserColumn($this->Config()->Get('plugin', 'usercol', ''))
|
||||
->SetPasswordColumn($this->Config()->Get('plugin', 'passcol', ''))
|
||||
->SetUser($this->Config()->Get('plugin', 'user', ''))
|
||||
->SetPassword($this->Config()->Get('plugin', 'password', ''))
|
||||
->SetEncrypt($this->Config()->Get('plugin', 'encrypt', ''))
|
||||
->SetAllowedEmails(\strtolower(\trim($this->Config()->Get('plugin', 'allowed_emails', ''))))
|
||||
->SetLogger($this->Manager()->Actions()->Logger())
|
||||
;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('engine')->SetLabel('Engine')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION)
|
||||
->SetDefaultValue(array('MySQL', 'PostgreSQL'))
|
||||
->SetDescription('Database Engine'),
|
||||
\RainLoop\Plugins\Property::NewInstance('host')->SetLabel('Host')
|
||||
->SetDefaultValue('127.0.0.1'),
|
||||
\RainLoop\Plugins\Property::NewInstance('port')->SetLabel('Port')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::INT)
|
||||
->SetDefaultValue(3306),
|
||||
\RainLoop\Plugins\Property::NewInstance('database')->SetLabel('Database')
|
||||
->SetDefaultValue('postfixadmin'),
|
||||
\RainLoop\Plugins\Property::NewInstance('table')->SetLabel('table')
|
||||
->SetDefaultValue('mailbox'),
|
||||
\RainLoop\Plugins\Property::NewInstance('usercol')->SetLabel('username column')
|
||||
->SetDefaultValue('username'),
|
||||
\RainLoop\Plugins\Property::NewInstance('passcol')->SetLabel('password column')
|
||||
->SetDefaultValue('password'),
|
||||
\RainLoop\Plugins\Property::NewInstance('user')->SetLabel('User')
|
||||
->SetDefaultValue('postfixadmin'),
|
||||
\RainLoop\Plugins\Property::NewInstance('password')->SetLabel('Password')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD)
|
||||
->SetDefaultValue(''),
|
||||
\RainLoop\Plugins\Property::NewInstance('encrypt')->SetLabel('Encrypt')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION)
|
||||
->SetDefaultValue(array('md5crypt', 'md5', 'system', 'cleartext', 'mysql_encrypt', 'SHA256-CRYPT', 'SHA512-CRYPT'))
|
||||
->SetDescription('In what way do you want the passwords to be crypted ?'),
|
||||
\RainLoop\Plugins\Property::NewInstance('allowed_emails')->SetLabel('Allowed emails')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT)
|
||||
->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@domain1.net user2@domain1.net *@domain2.net')
|
||||
->SetDefaultValue('*')
|
||||
);
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
class PostfixadminChangePasswordPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
public function Init()
|
||||
{
|
||||
$this->addHook('main.fabrica', 'MainFabrica');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function Supported()
|
||||
{
|
||||
if (!extension_loaded('pdo') || !class_exists('PDO'))
|
||||
{
|
||||
return 'The PHP extension PDO must be installed to use this plugin';
|
||||
}
|
||||
|
||||
$aDrivers = \PDO::getAvailableDrivers();
|
||||
if (!is_array($aDrivers) || (!in_array('mysql', $aDrivers) && !in_array('pgsql', $aDrivers)))
|
||||
{
|
||||
return 'The PHP extension PDO (mysql or pgsql) must be installed to use this plugin';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sName
|
||||
* @param mixed $oProvider
|
||||
*/
|
||||
public function MainFabrica($sName, &$oProvider)
|
||||
{
|
||||
switch ($sName)
|
||||
{
|
||||
case 'change-password':
|
||||
|
||||
include_once __DIR__.'/ChangePasswordPostfixAdminDriver.php';
|
||||
|
||||
$oProvider = new ChangePasswordPostfixAdminDriver();
|
||||
|
||||
$oProvider
|
||||
->SetEngine($this->Config()->Get('plugin', 'engine',''))
|
||||
->SetHost($this->Config()->Get('plugin', 'host', ''))
|
||||
->SetPort((int) $this->Config()->Get('plugin', 'port', 3306))
|
||||
->SetDatabase($this->Config()->Get('plugin', 'database', ''))
|
||||
->SetTable($this->Config()->Get('plugin', 'table', ''))
|
||||
->SetUserColumn($this->Config()->Get('plugin', 'usercol', ''))
|
||||
->SetPasswordColumn($this->Config()->Get('plugin', 'passcol', ''))
|
||||
->SetUser($this->Config()->Get('plugin', 'user', ''))
|
||||
->SetPassword($this->Config()->Get('plugin', 'password', ''))
|
||||
->SetEncrypt($this->Config()->Get('plugin', 'encrypt', ''))
|
||||
->SetAllowedEmails(\strtolower(\trim($this->Config()->Get('plugin', 'allowed_emails', ''))))
|
||||
->SetLogger($this->Manager()->Actions()->Logger())
|
||||
;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('engine')->SetLabel('Engine')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION)
|
||||
->SetDefaultValue(array('MySQL', 'PostgreSQL'))
|
||||
->SetDescription('Database Engine'),
|
||||
\RainLoop\Plugins\Property::NewInstance('host')->SetLabel('Host')
|
||||
->SetDefaultValue('127.0.0.1'),
|
||||
\RainLoop\Plugins\Property::NewInstance('port')->SetLabel('Port')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::INT)
|
||||
->SetDefaultValue(3306),
|
||||
\RainLoop\Plugins\Property::NewInstance('database')->SetLabel('Database')
|
||||
->SetDefaultValue('postfixadmin'),
|
||||
\RainLoop\Plugins\Property::NewInstance('table')->SetLabel('table')
|
||||
->SetDefaultValue('mailbox'),
|
||||
\RainLoop\Plugins\Property::NewInstance('usercol')->SetLabel('username column')
|
||||
->SetDefaultValue('username'),
|
||||
\RainLoop\Plugins\Property::NewInstance('passcol')->SetLabel('password column')
|
||||
->SetDefaultValue('password'),
|
||||
\RainLoop\Plugins\Property::NewInstance('user')->SetLabel('User')
|
||||
->SetDefaultValue('postfixadmin'),
|
||||
\RainLoop\Plugins\Property::NewInstance('password')->SetLabel('Password')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD)
|
||||
->SetDefaultValue(''),
|
||||
\RainLoop\Plugins\Property::NewInstance('encrypt')->SetLabel('Encrypt')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION)
|
||||
->SetDefaultValue(array('md5crypt', 'md5', 'system', 'cleartext', 'mysql_encrypt', 'SHA256-CRYPT', 'SHA512-CRYPT'))
|
||||
->SetDescription('In what way do you want the passwords to be crypted ?'),
|
||||
\RainLoop\Plugins\Property::NewInstance('allowed_emails')->SetLabel('Allowed emails')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT)
|
||||
->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@domain1.net user2@domain1.net *@domain2.net')
|
||||
->SetDefaultValue('*')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ function md5crypt($pw, $salt = "", $magic = "")
|
|||
{
|
||||
$ctx .= $pw[0];
|
||||
}
|
||||
|
||||
|
||||
$i = $i >> 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,151 +1,151 @@
|
|||
<?php
|
||||
|
||||
class RecaptchaPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function Init()
|
||||
{
|
||||
$this->UseLangs(true);
|
||||
|
||||
$this->addJs('js/recaptcha.js');
|
||||
|
||||
$this->addHook('ajax.action-pre-call', 'AjaxActionPreCall');
|
||||
$this->addHook('filter.ajax-response', 'FilterAjaxResponse');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('public_key')->SetLabel('Site key')
|
||||
->SetAllowedInJs(true)
|
||||
->SetDefaultValue(''),
|
||||
\RainLoop\Plugins\Property::NewInstance('private_key')->SetLabel('Secret key')
|
||||
->SetDefaultValue(''),
|
||||
\RainLoop\Plugins\Property::NewInstance('theme')->SetLabel('Theme')
|
||||
->SetAllowedInJs(true)
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION)
|
||||
->SetDefaultValue(array('light', 'dark')),
|
||||
\RainLoop\Plugins\Property::NewInstance('error_limit')->SetLabel('Limit')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION)
|
||||
->SetDefaultValue(array(0, 1, 2, 3, 4, 5))
|
||||
->SetDescription('')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function getCaptchaCacherKey()
|
||||
{
|
||||
return 'CaptchaNew/Login/'.\RainLoop\Utils::GetConnectionToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
private function getLimit()
|
||||
{
|
||||
$iConfigLimit = $this->Config()->Get('plugin', 'error_limit', 0);
|
||||
if (0 < $iConfigLimit)
|
||||
{
|
||||
$oCacher = $this->Manager()->Actions()->Cacher();
|
||||
$sLimit = $oCacher && $oCacher->IsInited() ? $oCacher->Get($this->getCaptchaCacherKey()) : '0';
|
||||
|
||||
if (0 < \strlen($sLimit) && \is_numeric($sLimit))
|
||||
{
|
||||
$iConfigLimit -= (int) $sLimit;
|
||||
}
|
||||
}
|
||||
|
||||
return $iConfigLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function FilterAppDataPluginSection($bAdmin, $bAuth, &$aData)
|
||||
{
|
||||
if (!$bAdmin && !$bAuth && \is_array($aData))
|
||||
{
|
||||
$aData['show_captcha_on_login'] = 1 > $this->getLimit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sAction
|
||||
*/
|
||||
public function AjaxActionPreCall($sAction)
|
||||
{
|
||||
if ('Login' === $sAction && 0 >= $this->getLimit())
|
||||
{
|
||||
$bResult = false;
|
||||
|
||||
$sResult = $this->Manager()->Actions()->Http()->SendPostRequest(
|
||||
'https://www.google.com/recaptcha/api/siteverify',
|
||||
array(
|
||||
'secret' => $this->Config()->Get('plugin', 'private_key', ''),
|
||||
'response' => $this->Manager()->Actions()->GetActionParam('RecaptchaResponse', '')
|
||||
)
|
||||
);
|
||||
|
||||
if ($sResult)
|
||||
{
|
||||
$aResp = @\json_decode($sResult, true);
|
||||
if (\is_array($aResp) && isset($aResp['success']) && $aResp['success'])
|
||||
{
|
||||
$bResult = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bResult)
|
||||
{
|
||||
$this->Manager()->Actions()->Logger()->Write('RecaptchaResponse:'.$sResult);
|
||||
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CaptchaError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sAction
|
||||
* @param array $aResponseItem
|
||||
*/
|
||||
public function FilterAjaxResponse($sAction, &$aResponseItem)
|
||||
{
|
||||
if ('Login' === $sAction && $aResponseItem && isset($aResponseItem['Result']))
|
||||
{
|
||||
$oCacher = $this->Manager()->Actions()->Cacher();
|
||||
$iConfigLimit = (int) $this->Config()->Get('plugin', 'error_limit', 0);
|
||||
|
||||
$sKey = $this->getCaptchaCacherKey();
|
||||
|
||||
if (0 < $iConfigLimit && $oCacher && $oCacher->IsInited())
|
||||
{
|
||||
if (false === $aResponseItem['Result'])
|
||||
{
|
||||
$iLimit = 0;
|
||||
$sLimut = $oCacher->Get($sKey);
|
||||
if (0 < \strlen($sLimut) && \is_numeric($sLimut))
|
||||
{
|
||||
$iLimit = (int) $sLimut;
|
||||
}
|
||||
|
||||
$oCacher->Set($sKey, ++$iLimit);
|
||||
|
||||
if ($iConfigLimit <= $iLimit)
|
||||
{
|
||||
$aResponseItem['Captcha'] = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oCacher->Delete($sKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
class RecaptchaPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function Init()
|
||||
{
|
||||
$this->UseLangs(true);
|
||||
|
||||
$this->addJs('js/recaptcha.js');
|
||||
|
||||
$this->addHook('ajax.action-pre-call', 'AjaxActionPreCall');
|
||||
$this->addHook('filter.ajax-response', 'FilterAjaxResponse');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('public_key')->SetLabel('Site key')
|
||||
->SetAllowedInJs(true)
|
||||
->SetDefaultValue(''),
|
||||
\RainLoop\Plugins\Property::NewInstance('private_key')->SetLabel('Secret key')
|
||||
->SetDefaultValue(''),
|
||||
\RainLoop\Plugins\Property::NewInstance('theme')->SetLabel('Theme')
|
||||
->SetAllowedInJs(true)
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION)
|
||||
->SetDefaultValue(array('light', 'dark')),
|
||||
\RainLoop\Plugins\Property::NewInstance('error_limit')->SetLabel('Limit')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION)
|
||||
->SetDefaultValue(array(0, 1, 2, 3, 4, 5))
|
||||
->SetDescription('')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function getCaptchaCacherKey()
|
||||
{
|
||||
return 'CaptchaNew/Login/'.\RainLoop\Utils::GetConnectionToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
private function getLimit()
|
||||
{
|
||||
$iConfigLimit = $this->Config()->Get('plugin', 'error_limit', 0);
|
||||
if (0 < $iConfigLimit)
|
||||
{
|
||||
$oCacher = $this->Manager()->Actions()->Cacher();
|
||||
$sLimit = $oCacher && $oCacher->IsInited() ? $oCacher->Get($this->getCaptchaCacherKey()) : '0';
|
||||
|
||||
if (0 < \strlen($sLimit) && \is_numeric($sLimit))
|
||||
{
|
||||
$iConfigLimit -= (int) $sLimit;
|
||||
}
|
||||
}
|
||||
|
||||
return $iConfigLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function FilterAppDataPluginSection($bAdmin, $bAuth, &$aData)
|
||||
{
|
||||
if (!$bAdmin && !$bAuth && \is_array($aData))
|
||||
{
|
||||
$aData['show_captcha_on_login'] = 1 > $this->getLimit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sAction
|
||||
*/
|
||||
public function AjaxActionPreCall($sAction)
|
||||
{
|
||||
if ('Login' === $sAction && 0 >= $this->getLimit())
|
||||
{
|
||||
$bResult = false;
|
||||
|
||||
$sResult = $this->Manager()->Actions()->Http()->SendPostRequest(
|
||||
'https://www.google.com/recaptcha/api/siteverify',
|
||||
array(
|
||||
'secret' => $this->Config()->Get('plugin', 'private_key', ''),
|
||||
'response' => $this->Manager()->Actions()->GetActionParam('RecaptchaResponse', '')
|
||||
)
|
||||
);
|
||||
|
||||
if ($sResult)
|
||||
{
|
||||
$aResp = @\json_decode($sResult, true);
|
||||
if (\is_array($aResp) && isset($aResp['success']) && $aResp['success'])
|
||||
{
|
||||
$bResult = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bResult)
|
||||
{
|
||||
$this->Manager()->Actions()->Logger()->Write('RecaptchaResponse:'.$sResult);
|
||||
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CaptchaError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sAction
|
||||
* @param array $aResponseItem
|
||||
*/
|
||||
public function FilterAjaxResponse($sAction, &$aResponseItem)
|
||||
{
|
||||
if ('Login' === $sAction && $aResponseItem && isset($aResponseItem['Result']))
|
||||
{
|
||||
$oCacher = $this->Manager()->Actions()->Cacher();
|
||||
$iConfigLimit = (int) $this->Config()->Get('plugin', 'error_limit', 0);
|
||||
|
||||
$sKey = $this->getCaptchaCacherKey();
|
||||
|
||||
if (0 < $iConfigLimit && $oCacher && $oCacher->IsInited())
|
||||
{
|
||||
if (false === $aResponseItem['Result'])
|
||||
{
|
||||
$iLimit = 0;
|
||||
$sLimut = $oCacher->Get($sKey);
|
||||
if (0 < \strlen($sLimut) && \is_numeric($sLimut))
|
||||
{
|
||||
$iLimit = (int) $sLimut;
|
||||
}
|
||||
|
||||
$oCacher->Set($sKey, ++$iLimit);
|
||||
|
||||
if ($iConfigLimit <= $iLimit)
|
||||
{
|
||||
$aResponseItem['Captcha'] = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oCacher->Delete($sKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,95 +1,95 @@
|
|||
(function ($, window) {
|
||||
|
||||
$(function () {
|
||||
|
||||
var
|
||||
nId = null,
|
||||
bStarted = false
|
||||
;
|
||||
|
||||
function ShowRecaptcha()
|
||||
{
|
||||
if (window.grecaptcha && window.rl)
|
||||
{
|
||||
if (null === nId)
|
||||
{
|
||||
var
|
||||
oEl = null,
|
||||
oLink = $('.plugin-mark-Login-BottomControlGroup')
|
||||
;
|
||||
|
||||
if (oLink && oLink[0])
|
||||
{
|
||||
oEl = $('<div class="controls"></div>');
|
||||
|
||||
$(oLink[0]).after(oEl);
|
||||
|
||||
nId = window.grecaptcha.render(oEl[0], {
|
||||
'sitekey': window.rl.pluginSettingsGet('recaptcha', 'public_key'),
|
||||
'theme': window.rl.pluginSettingsGet('recaptcha', 'theme')
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.__globalShowRecaptcha = ShowRecaptcha;
|
||||
|
||||
function StartRecaptcha()
|
||||
{
|
||||
if (!window.grecaptcha && window.rl)
|
||||
{
|
||||
$.getScript('https://www.google.com/recaptcha/api.js?onload=__globalShowRecaptcha&render=explicit&hl=' + window.rl.settingsGet('Language'));
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowRecaptcha();
|
||||
}
|
||||
}
|
||||
|
||||
if (window.rl)
|
||||
{
|
||||
window.rl.addHook('user-login-submit', function (fSubmitResult) {
|
||||
if (null !== nId && !window.grecaptcha.getResponse(nId))
|
||||
{
|
||||
fSubmitResult(105);
|
||||
}
|
||||
});
|
||||
|
||||
window.rl.addHook('view-model-on-show', function (sName, oViewModel) {
|
||||
if (!bStarted && oViewModel &&
|
||||
('View:RainLoop:Login' === sName || 'View/App/Login' === sName || 'LoginViewModel' === sName || 'LoginAppView' === sName) &&
|
||||
window.rl.pluginSettingsGet('recaptcha', 'show_captcha_on_login'))
|
||||
{
|
||||
bStarted = true;
|
||||
StartRecaptcha();
|
||||
}
|
||||
});
|
||||
|
||||
window.rl.addHook('ajax-default-request', function (sAction, oParameters) {
|
||||
if ('Login' === sAction && oParameters && null !== nId && window.grecaptcha)
|
||||
{
|
||||
oParameters['RecaptchaResponse'] = window.grecaptcha.getResponse(nId);
|
||||
}
|
||||
});
|
||||
|
||||
window.rl.addHook('ajax-default-response', function (sAction, oData, sType) {
|
||||
if ('Login' === sAction)
|
||||
{
|
||||
if (!oData || 'success' !== sType || !oData['Result'])
|
||||
{
|
||||
if (null !== nId && window.grecaptcha)
|
||||
{
|
||||
window.grecaptcha.reset(nId);
|
||||
}
|
||||
else if (oData && oData['Captcha'])
|
||||
{
|
||||
StartRecaptcha();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
(function ($, window) {
|
||||
|
||||
$(function () {
|
||||
|
||||
var
|
||||
nId = null,
|
||||
bStarted = false
|
||||
;
|
||||
|
||||
function ShowRecaptcha()
|
||||
{
|
||||
if (window.grecaptcha && window.rl)
|
||||
{
|
||||
if (null === nId)
|
||||
{
|
||||
var
|
||||
oEl = null,
|
||||
oLink = $('.plugin-mark-Login-BottomControlGroup')
|
||||
;
|
||||
|
||||
if (oLink && oLink[0])
|
||||
{
|
||||
oEl = $('<div class="controls"></div>');
|
||||
|
||||
$(oLink[0]).after(oEl);
|
||||
|
||||
nId = window.grecaptcha.render(oEl[0], {
|
||||
'sitekey': window.rl.pluginSettingsGet('recaptcha', 'public_key'),
|
||||
'theme': window.rl.pluginSettingsGet('recaptcha', 'theme')
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.__globalShowRecaptcha = ShowRecaptcha;
|
||||
|
||||
function StartRecaptcha()
|
||||
{
|
||||
if (!window.grecaptcha && window.rl)
|
||||
{
|
||||
$.getScript('https://www.google.com/recaptcha/api.js?onload=__globalShowRecaptcha&render=explicit&hl=' + window.rl.settingsGet('Language'));
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowRecaptcha();
|
||||
}
|
||||
}
|
||||
|
||||
if (window.rl)
|
||||
{
|
||||
window.rl.addHook('user-login-submit', function (fSubmitResult) {
|
||||
if (null !== nId && !window.grecaptcha.getResponse(nId))
|
||||
{
|
||||
fSubmitResult(105);
|
||||
}
|
||||
});
|
||||
|
||||
window.rl.addHook('view-model-on-show', function (sName, oViewModel) {
|
||||
if (!bStarted && oViewModel &&
|
||||
('View:RainLoop:Login' === sName || 'View/App/Login' === sName || 'LoginViewModel' === sName || 'LoginAppView' === sName) &&
|
||||
window.rl.pluginSettingsGet('recaptcha', 'show_captcha_on_login'))
|
||||
{
|
||||
bStarted = true;
|
||||
StartRecaptcha();
|
||||
}
|
||||
});
|
||||
|
||||
window.rl.addHook('ajax-default-request', function (sAction, oParameters) {
|
||||
if ('Login' === sAction && oParameters && null !== nId && window.grecaptcha)
|
||||
{
|
||||
oParameters['RecaptchaResponse'] = window.grecaptcha.getResponse(nId);
|
||||
}
|
||||
});
|
||||
|
||||
window.rl.addHook('ajax-default-response', function (sAction, oData, sType) {
|
||||
if ('Login' === sAction)
|
||||
{
|
||||
if (!oData || 'success' !== sType || !oData['Result'])
|
||||
{
|
||||
if (null !== nId && window.grecaptcha)
|
||||
{
|
||||
window.grecaptcha.reset(nId);
|
||||
}
|
||||
else if (oData && oData['Captcha'])
|
||||
{
|
||||
StartRecaptcha();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}($, window));
|
|
@ -1,275 +1,275 @@
|
|||
/* Snowfall pure js
|
||||
====================================================================
|
||||
LICENSE
|
||||
====================================================================
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
====================================================================
|
||||
|
||||
1.0
|
||||
Wanted to rewrite my snow plugin to use pure JS so you werent necessarily tied to using a framework.
|
||||
Does not include a selector engine or anything, just pass elements to it using standard JS selectors.
|
||||
|
||||
Does not clear snow currently. Collection portion removed just for ease of testing will add back in next version
|
||||
|
||||
Theres a few ways to call the snow you could do it the following way by directly passing the selector,
|
||||
|
||||
snowFall.snow(document.getElementsByTagName("body"), {options});
|
||||
|
||||
or you could save the selector results to a variable, and then call it
|
||||
|
||||
var elements = document.getElementsByClassName('yourclass');
|
||||
snowFall.snow(elements, {options});
|
||||
|
||||
Options are all the same as the plugin except clear, and collection
|
||||
|
||||
values for snow options are
|
||||
|
||||
flakeCount,
|
||||
flakeColor,
|
||||
flakeIndex,
|
||||
minSize,
|
||||
maxSize,
|
||||
minSpeed,
|
||||
maxSpeed,
|
||||
round, true or false, makes the snowflakes rounded if the browser supports it.
|
||||
shadow true or false, gives the snowflakes a shadow if the browser supports it.
|
||||
|
||||
*/
|
||||
|
||||
// Paul Irish requestAnimationFrame polyfill
|
||||
(function(window) {
|
||||
var lastTime = 0;
|
||||
var vendors = ['webkit', 'moz'];
|
||||
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
|
||||
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
|
||||
window.cancelAnimationFrame =
|
||||
window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
|
||||
}
|
||||
|
||||
if (!window.requestAnimationFrame)
|
||||
window.requestAnimationFrame = function(callback, element) {
|
||||
var currTime = new Date().getTime();
|
||||
var timeToCall = window.Math.max(0, 16 - (currTime - lastTime));
|
||||
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
|
||||
timeToCall);
|
||||
lastTime = currTime + timeToCall;
|
||||
return id;
|
||||
};
|
||||
|
||||
if (!window.cancelAnimationFrame)
|
||||
window.cancelAnimationFrame = function(id) {
|
||||
clearTimeout(id);
|
||||
};
|
||||
}(window));
|
||||
|
||||
var snowFall = (function(){
|
||||
function jSnow(){
|
||||
// local methods
|
||||
var defaults = {
|
||||
flakeCount : 35,
|
||||
flakeColor : '#ffffff',
|
||||
flakeIndex: 999999,
|
||||
minSize : 1,
|
||||
maxSize : 2,
|
||||
minSpeed : 1,
|
||||
maxSpeed : 5,
|
||||
round : false,
|
||||
shadow : false,
|
||||
collection : false,
|
||||
image : false,
|
||||
collectionHeight : 40
|
||||
},
|
||||
element = {},
|
||||
flakes = [],
|
||||
flakeId = 0,
|
||||
elHeight = 0,
|
||||
elWidth = 0,
|
||||
elTop = 0,
|
||||
elLeft = 0,
|
||||
widthOffset = 0,
|
||||
snowTimeout = 0,
|
||||
// For extending the default object with properties
|
||||
extend = function(obj, extObj){
|
||||
for(var i in extObj){
|
||||
if(obj.hasOwnProperty(i)){
|
||||
obj[i] = extObj[i];
|
||||
}
|
||||
}
|
||||
},
|
||||
// random between range
|
||||
random = function random(min, max){
|
||||
return window.Math.round(min + window.Math.random()*(max-min));
|
||||
},
|
||||
// Set multiple styles at once.
|
||||
setStyle = function(element, props)
|
||||
{
|
||||
for (var property in props){
|
||||
element.style[property] = props[property] + ((property === 'width' || property === 'height') ? 'px' : '');
|
||||
}
|
||||
},
|
||||
// snowflake
|
||||
flake = function(_x, _y, _size, _speed, _id)
|
||||
{
|
||||
// Flake properties
|
||||
this.id = _id;
|
||||
this.x = _x + elLeft;
|
||||
this.y = _y + elTop;
|
||||
this.size = _size;
|
||||
this.speed = _speed;
|
||||
this.step = 0;
|
||||
this.stepSize = random(1,10) / 100;
|
||||
|
||||
if(defaults.collection){
|
||||
this.target = defaults.collection[random(0,defaults.collection.length-1)];
|
||||
}
|
||||
|
||||
var flakeObj = null;
|
||||
|
||||
if(defaults.image){
|
||||
flakeObj = new Image();
|
||||
flakeObj.src = defaults.image;
|
||||
}else{
|
||||
flakeObj = window.document.createElement("div");
|
||||
setStyle(flakeObj, {'background' : defaults.flakeColor});
|
||||
}
|
||||
|
||||
flakeObj.className = 'snowfall-flakes';
|
||||
flakeObj.setAttribute('id','flake-' + this.id);
|
||||
setStyle(flakeObj, {'width' : this.size, 'height' : this.size, 'position' : 'absolute', 'top' : this.y, 'left' : this.x, 'fontSize' : 0, 'zIndex' : defaults.flakeIndex});
|
||||
|
||||
// This adds the style to make the snowflakes round via border radius property
|
||||
if(defaults.round){
|
||||
setStyle(flakeObj,{'-moz-border-radius' : ~~(defaults.maxSize) + 'px', '-webkit-border-radius' : ~~(defaults.maxSize) + 'px', 'borderRadius' : ~~(defaults.maxSize) + 'px'});
|
||||
}
|
||||
|
||||
// This adds shadows just below the snowflake so they pop a bit on lighter colored web pages
|
||||
if(defaults.shadow){
|
||||
setStyle(flakeObj,{'-moz-box-shadow' : '1px 1px 1px #555', '-webkit-box-shadow' : '1px 1px 1px #555', 'boxShadow' : '1px 1px 1px #555'});
|
||||
}
|
||||
|
||||
window.document.body.appendChild(flakeObj);
|
||||
|
||||
this.element = flakeObj;
|
||||
|
||||
// Update function, used to update the snow flakes, and checks current snowflake against bounds
|
||||
this.update = function(){
|
||||
this.y += this.speed;
|
||||
|
||||
if(this.y > (elTop + elHeight) - (this.size + 6)){
|
||||
this.reset();
|
||||
}
|
||||
|
||||
this.element.style.top = this.y + 'px';
|
||||
this.element.style.left = ~~this.x + 'px';
|
||||
|
||||
this.step += this.stepSize;
|
||||
this.x += window.Math.cos(this.step);
|
||||
|
||||
if(this.x > (elLeft + elWidth) - widthOffset || this.x < widthOffset){
|
||||
this.reset();
|
||||
}
|
||||
};
|
||||
|
||||
// Resets the snowflake once it reaches one of the bounds set
|
||||
this.reset = function(){
|
||||
this.y = elTop;
|
||||
this.x = elLeft + random(widthOffset, elWidth - widthOffset);
|
||||
this.stepSize = random(1,10) / 100;
|
||||
this.size = random((defaults.minSize * 100), (defaults.maxSize * 100)) / 100;
|
||||
this.speed = random(defaults.minSpeed, defaults.maxSpeed);
|
||||
};
|
||||
},
|
||||
// this controls flow of the updating snow
|
||||
animateSnow = function(){
|
||||
for(var i = 0; i < flakes.length; i += 1){
|
||||
flakes[i].update();
|
||||
}
|
||||
snowTimeout = requestAnimationFrame(function(){animateSnow();});
|
||||
};
|
||||
return{
|
||||
snow : function(_element, _options){
|
||||
extend(defaults, _options);
|
||||
|
||||
//init the element vars
|
||||
element = _element;
|
||||
elHeight = element.clientHeight,
|
||||
elWidth = element.offsetWidth;
|
||||
elTop = element.offsetTop;
|
||||
elLeft = element.offsetLeft;
|
||||
|
||||
element.snow = this;
|
||||
|
||||
// if this is the body the offset is a little different
|
||||
if(element.tagName.toLowerCase() === 'body'){
|
||||
widthOffset = 25;
|
||||
}
|
||||
|
||||
// Bind the window resize event so we can get the innerHeight again
|
||||
window.onresize = function(){
|
||||
elHeight = element.clientHeight;
|
||||
elWidth = element.offsetWidth;
|
||||
elTop = element.offsetTop;
|
||||
elLeft = element.offsetLeft;
|
||||
};
|
||||
|
||||
// initialize the flakes
|
||||
for(var i = 0; i < defaults.flakeCount; i+=1){
|
||||
flakeId = flakes.length;
|
||||
flakes.push(new flake(random(widthOffset,elWidth - widthOffset), random(0, elHeight), random((defaults.minSize * 100), (defaults.maxSize * 100)) / 100, random(defaults.minSpeed, defaults.maxSpeed), flakeId));
|
||||
}
|
||||
// start the snow
|
||||
animateSnow();
|
||||
},
|
||||
clear : function(){
|
||||
var flakeChildren = null;
|
||||
|
||||
if(!element.getElementsByClassName){
|
||||
flakeChildren = element.querySelectorAll('.snowfall-flakes');
|
||||
}else{
|
||||
flakeChildren = element.getElementsByClassName('snowfall-flakes');
|
||||
}
|
||||
|
||||
var flakeChilLen = flakeChildren.length;
|
||||
while(flakeChilLen--){
|
||||
element.removeChild(flakeChildren[flakeChilLen]);
|
||||
}
|
||||
|
||||
flakes = [];
|
||||
cancelAnimationFrame(snowTimeout);
|
||||
}
|
||||
};
|
||||
};
|
||||
return{
|
||||
snow : function(elements, options){
|
||||
if(typeof(options) === 'string'){
|
||||
if(elements.length > 0){
|
||||
for(var i = 0; i < elements.length; i++){
|
||||
if(elements[i].snow){
|
||||
elements[i].snow.clear();
|
||||
}
|
||||
}
|
||||
}else{
|
||||
elements.snow.clear();
|
||||
}
|
||||
}else{
|
||||
if(elements.length > 0){
|
||||
for(var i = 0; i < elements.length; i++){
|
||||
new jSnow().snow(elements[i], options);
|
||||
}
|
||||
}else{
|
||||
new jSnow().snow(elements, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
/* Snowfall pure js
|
||||
====================================================================
|
||||
LICENSE
|
||||
====================================================================
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
====================================================================
|
||||
|
||||
1.0
|
||||
Wanted to rewrite my snow plugin to use pure JS so you werent necessarily tied to using a framework.
|
||||
Does not include a selector engine or anything, just pass elements to it using standard JS selectors.
|
||||
|
||||
Does not clear snow currently. Collection portion removed just for ease of testing will add back in next version
|
||||
|
||||
Theres a few ways to call the snow you could do it the following way by directly passing the selector,
|
||||
|
||||
snowFall.snow(document.getElementsByTagName("body"), {options});
|
||||
|
||||
or you could save the selector results to a variable, and then call it
|
||||
|
||||
var elements = document.getElementsByClassName('yourclass');
|
||||
snowFall.snow(elements, {options});
|
||||
|
||||
Options are all the same as the plugin except clear, and collection
|
||||
|
||||
values for snow options are
|
||||
|
||||
flakeCount,
|
||||
flakeColor,
|
||||
flakeIndex,
|
||||
minSize,
|
||||
maxSize,
|
||||
minSpeed,
|
||||
maxSpeed,
|
||||
round, true or false, makes the snowflakes rounded if the browser supports it.
|
||||
shadow true or false, gives the snowflakes a shadow if the browser supports it.
|
||||
|
||||
*/
|
||||
|
||||
// Paul Irish requestAnimationFrame polyfill
|
||||
(function(window) {
|
||||
var lastTime = 0;
|
||||
var vendors = ['webkit', 'moz'];
|
||||
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
|
||||
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
|
||||
window.cancelAnimationFrame =
|
||||
window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
|
||||
}
|
||||
|
||||
if (!window.requestAnimationFrame)
|
||||
window.requestAnimationFrame = function(callback, element) {
|
||||
var currTime = new Date().getTime();
|
||||
var timeToCall = window.Math.max(0, 16 - (currTime - lastTime));
|
||||
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
|
||||
timeToCall);
|
||||
lastTime = currTime + timeToCall;
|
||||
return id;
|
||||
};
|
||||
|
||||
if (!window.cancelAnimationFrame)
|
||||
window.cancelAnimationFrame = function(id) {
|
||||
clearTimeout(id);
|
||||
};
|
||||
}(window));
|
||||
|
||||
var snowFall = (function(){
|
||||
function jSnow(){
|
||||
// local methods
|
||||
var defaults = {
|
||||
flakeCount : 35,
|
||||
flakeColor : '#ffffff',
|
||||
flakeIndex: 999999,
|
||||
minSize : 1,
|
||||
maxSize : 2,
|
||||
minSpeed : 1,
|
||||
maxSpeed : 5,
|
||||
round : false,
|
||||
shadow : false,
|
||||
collection : false,
|
||||
image : false,
|
||||
collectionHeight : 40
|
||||
},
|
||||
element = {},
|
||||
flakes = [],
|
||||
flakeId = 0,
|
||||
elHeight = 0,
|
||||
elWidth = 0,
|
||||
elTop = 0,
|
||||
elLeft = 0,
|
||||
widthOffset = 0,
|
||||
snowTimeout = 0,
|
||||
// For extending the default object with properties
|
||||
extend = function(obj, extObj){
|
||||
for(var i in extObj){
|
||||
if(obj.hasOwnProperty(i)){
|
||||
obj[i] = extObj[i];
|
||||
}
|
||||
}
|
||||
},
|
||||
// random between range
|
||||
random = function random(min, max){
|
||||
return window.Math.round(min + window.Math.random()*(max-min));
|
||||
},
|
||||
// Set multiple styles at once.
|
||||
setStyle = function(element, props)
|
||||
{
|
||||
for (var property in props){
|
||||
element.style[property] = props[property] + ((property === 'width' || property === 'height') ? 'px' : '');
|
||||
}
|
||||
},
|
||||
// snowflake
|
||||
flake = function(_x, _y, _size, _speed, _id)
|
||||
{
|
||||
// Flake properties
|
||||
this.id = _id;
|
||||
this.x = _x + elLeft;
|
||||
this.y = _y + elTop;
|
||||
this.size = _size;
|
||||
this.speed = _speed;
|
||||
this.step = 0;
|
||||
this.stepSize = random(1,10) / 100;
|
||||
|
||||
if(defaults.collection){
|
||||
this.target = defaults.collection[random(0,defaults.collection.length-1)];
|
||||
}
|
||||
|
||||
var flakeObj = null;
|
||||
|
||||
if(defaults.image){
|
||||
flakeObj = new Image();
|
||||
flakeObj.src = defaults.image;
|
||||
}else{
|
||||
flakeObj = window.document.createElement("div");
|
||||
setStyle(flakeObj, {'background' : defaults.flakeColor});
|
||||
}
|
||||
|
||||
flakeObj.className = 'snowfall-flakes';
|
||||
flakeObj.setAttribute('id','flake-' + this.id);
|
||||
setStyle(flakeObj, {'width' : this.size, 'height' : this.size, 'position' : 'absolute', 'top' : this.y, 'left' : this.x, 'fontSize' : 0, 'zIndex' : defaults.flakeIndex});
|
||||
|
||||
// This adds the style to make the snowflakes round via border radius property
|
||||
if(defaults.round){
|
||||
setStyle(flakeObj,{'-moz-border-radius' : ~~(defaults.maxSize) + 'px', '-webkit-border-radius' : ~~(defaults.maxSize) + 'px', 'borderRadius' : ~~(defaults.maxSize) + 'px'});
|
||||
}
|
||||
|
||||
// This adds shadows just below the snowflake so they pop a bit on lighter colored web pages
|
||||
if(defaults.shadow){
|
||||
setStyle(flakeObj,{'-moz-box-shadow' : '1px 1px 1px #555', '-webkit-box-shadow' : '1px 1px 1px #555', 'boxShadow' : '1px 1px 1px #555'});
|
||||
}
|
||||
|
||||
window.document.body.appendChild(flakeObj);
|
||||
|
||||
this.element = flakeObj;
|
||||
|
||||
// Update function, used to update the snow flakes, and checks current snowflake against bounds
|
||||
this.update = function(){
|
||||
this.y += this.speed;
|
||||
|
||||
if(this.y > (elTop + elHeight) - (this.size + 6)){
|
||||
this.reset();
|
||||
}
|
||||
|
||||
this.element.style.top = this.y + 'px';
|
||||
this.element.style.left = ~~this.x + 'px';
|
||||
|
||||
this.step += this.stepSize;
|
||||
this.x += window.Math.cos(this.step);
|
||||
|
||||
if(this.x > (elLeft + elWidth) - widthOffset || this.x < widthOffset){
|
||||
this.reset();
|
||||
}
|
||||
};
|
||||
|
||||
// Resets the snowflake once it reaches one of the bounds set
|
||||
this.reset = function(){
|
||||
this.y = elTop;
|
||||
this.x = elLeft + random(widthOffset, elWidth - widthOffset);
|
||||
this.stepSize = random(1,10) / 100;
|
||||
this.size = random((defaults.minSize * 100), (defaults.maxSize * 100)) / 100;
|
||||
this.speed = random(defaults.minSpeed, defaults.maxSpeed);
|
||||
};
|
||||
},
|
||||
// this controls flow of the updating snow
|
||||
animateSnow = function(){
|
||||
for(var i = 0; i < flakes.length; i += 1){
|
||||
flakes[i].update();
|
||||
}
|
||||
snowTimeout = requestAnimationFrame(function(){animateSnow();});
|
||||
};
|
||||
return{
|
||||
snow : function(_element, _options){
|
||||
extend(defaults, _options);
|
||||
|
||||
//init the element vars
|
||||
element = _element;
|
||||
elHeight = element.clientHeight,
|
||||
elWidth = element.offsetWidth;
|
||||
elTop = element.offsetTop;
|
||||
elLeft = element.offsetLeft;
|
||||
|
||||
element.snow = this;
|
||||
|
||||
// if this is the body the offset is a little different
|
||||
if(element.tagName.toLowerCase() === 'body'){
|
||||
widthOffset = 25;
|
||||
}
|
||||
|
||||
// Bind the window resize event so we can get the innerHeight again
|
||||
window.onresize = function(){
|
||||
elHeight = element.clientHeight;
|
||||
elWidth = element.offsetWidth;
|
||||
elTop = element.offsetTop;
|
||||
elLeft = element.offsetLeft;
|
||||
};
|
||||
|
||||
// initialize the flakes
|
||||
for(var i = 0; i < defaults.flakeCount; i+=1){
|
||||
flakeId = flakes.length;
|
||||
flakes.push(new flake(random(widthOffset,elWidth - widthOffset), random(0, elHeight), random((defaults.minSize * 100), (defaults.maxSize * 100)) / 100, random(defaults.minSpeed, defaults.maxSpeed), flakeId));
|
||||
}
|
||||
// start the snow
|
||||
animateSnow();
|
||||
},
|
||||
clear : function(){
|
||||
var flakeChildren = null;
|
||||
|
||||
if(!element.getElementsByClassName){
|
||||
flakeChildren = element.querySelectorAll('.snowfall-flakes');
|
||||
}else{
|
||||
flakeChildren = element.getElementsByClassName('snowfall-flakes');
|
||||
}
|
||||
|
||||
var flakeChilLen = flakeChildren.length;
|
||||
while(flakeChilLen--){
|
||||
element.removeChild(flakeChildren[flakeChilLen]);
|
||||
}
|
||||
|
||||
flakes = [];
|
||||
cancelAnimationFrame(snowTimeout);
|
||||
}
|
||||
};
|
||||
};
|
||||
return{
|
||||
snow : function(elements, options){
|
||||
if(typeof(options) === 'string'){
|
||||
if(elements.length > 0){
|
||||
for(var i = 0; i < elements.length; i++){
|
||||
if(elements[i].snow){
|
||||
elements[i].snow.clear();
|
||||
}
|
||||
}
|
||||
}else{
|
||||
elements.snow.clear();
|
||||
}
|
||||
}else{
|
||||
if(elements.length > 0){
|
||||
for(var i = 0; i < elements.length; i++){
|
||||
new jSnow().snow(elements[i], options);
|
||||
}
|
||||
}else{
|
||||
new jSnow().snow(elements, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
|
@ -1282,7 +1282,6 @@ class Actions
|
|||
'forgotPasswordLinkUrl' => \trim($oConfig->Get('login', 'forgot_password_link_url', '')),
|
||||
'registrationLinkUrl' => \trim($oConfig->Get('login', 'registration_link_url', '')),
|
||||
'hideSubmitButton' => (bool) $oConfig->Get('login', 'hide_submit_button', true),
|
||||
'jsHash' => \md5(\RainLoop\Utils::GetConnectionToken()),
|
||||
'useImapThread' => (bool) $oConfig->Get('labs', 'use_imap_thread', false),
|
||||
'useImapSubscribe' => (bool) $oConfig->Get('labs', 'use_imap_list_subscribe', true),
|
||||
'allowAppendMessage' => (bool) $oConfig->Get('labs', 'allow_message_append', false),
|
||||
|
|
40
vendors/Progress.js/src/progress.js
vendored
40
vendors/Progress.js/src/progress.js
vendored
|
@ -29,7 +29,7 @@
|
|||
function ProgressJs(obj) {
|
||||
|
||||
if (typeof obj.length != 'undefined') {
|
||||
this._targetElement = obj;
|
||||
this._targetElement = obj;
|
||||
} else {
|
||||
this._targetElement = [obj];
|
||||
}
|
||||
|
@ -37,7 +37,7 @@
|
|||
if (typeof window._progressjsId === 'undefined')
|
||||
window._progressjsId = 1;
|
||||
|
||||
if (typeof window._progressjsIntervals === 'undefined')
|
||||
if (typeof window._progressjsIntervals === 'undefined')
|
||||
window._progressjsIntervals = {};
|
||||
|
||||
this._options = {
|
||||
|
@ -54,7 +54,7 @@
|
|||
* Start progress for specific element(s)
|
||||
*
|
||||
* @api private
|
||||
* @method _createContainer
|
||||
* @method _createContainer
|
||||
*/
|
||||
function _startProgress() {
|
||||
|
||||
|
@ -79,7 +79,7 @@
|
|||
* @param {Object} targetElement
|
||||
*/
|
||||
function _setProgress(targetElement) {
|
||||
|
||||
|
||||
//if the target element already as `data-progressjs`, ignore the init
|
||||
if (targetElement.hasAttribute("data-progressjs"))
|
||||
return;
|
||||
|
@ -88,7 +88,7 @@
|
|||
var targetElementOffset = _getOffset.call(this, targetElement);
|
||||
|
||||
targetElement.setAttribute("data-progressjs", window._progressjsId);
|
||||
|
||||
|
||||
var progressElementContainer = document.createElement('div');
|
||||
progressElementContainer.className = 'progressjs-progress progressjs-theme-' + this._options.theme;
|
||||
|
||||
|
@ -110,7 +110,7 @@
|
|||
progressPercentElement.innerHTML = "1%";
|
||||
|
||||
progressElement.appendChild(progressPercentElement);
|
||||
|
||||
|
||||
if (this._options.overlayMode && targetElement.tagName.toLowerCase() === 'body') {
|
||||
//if we have `body` for target element and also overlay mode is enable, we should use a different
|
||||
//position for progress bar container element
|
||||
|
@ -164,7 +164,7 @@
|
|||
*/
|
||||
function _setPercentFor(targetElement, percent) {
|
||||
var self = this;
|
||||
|
||||
|
||||
//prevent overflow!
|
||||
if (percent >= 100)
|
||||
percent = 100;
|
||||
|
@ -191,7 +191,7 @@
|
|||
if (existingPercent > currentPercent) {
|
||||
increasement = false;
|
||||
}
|
||||
|
||||
|
||||
var intervalIn = 10;
|
||||
function changePercentTimer(percentElement, existingPercent, currentPercent) {
|
||||
//calculate the distance between two percents
|
||||
|
@ -210,17 +210,17 @@
|
|||
setTimeout(function() { changePercentTimer(percentElement, existingPercent, currentPercent); }, intervalIn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
changePercentTimer(percentElement, existingPercent, currentPercent);
|
||||
|
||||
|
||||
})(percentElement, existingPercent, parseInt(percent));
|
||||
|
||||
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the progress bar element
|
||||
* Get the progress bar element
|
||||
*
|
||||
* @api private
|
||||
* @method _getPercentElement
|
||||
|
@ -228,7 +228,7 @@
|
|||
*/
|
||||
function _getPercentElement(targetElement) {
|
||||
var progressjsId = parseInt(targetElement.getAttribute('data-progressjs'));
|
||||
return document.querySelector('.progressjs-container > .progressjs-progress[data-progressjs="' + progressjsId + '"] > .progressjs-inner');
|
||||
return document.querySelector('.progressjs-container > .progressjs-progress[data-progressjs="' + progressjsId + '"] > .progressjs-inner');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -241,9 +241,9 @@
|
|||
*/
|
||||
function _autoIncrease(size, millisecond) {
|
||||
var self = this;
|
||||
|
||||
|
||||
var progressjsId = parseInt(this._targetElement[0].getAttribute('data-progressjs'));
|
||||
|
||||
|
||||
if (typeof window._progressjsIntervals[progressjsId] != 'undefined') {
|
||||
clearInterval(window._progressjsIntervals[progressjsId]);
|
||||
}
|
||||
|
@ -273,7 +273,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
* Close and remove progress bar
|
||||
* Close and remove progress bar
|
||||
*
|
||||
* @api private
|
||||
* @method _end
|
||||
|
@ -288,10 +288,10 @@
|
|||
} else {
|
||||
this._onBeforeEndCallback.call(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var progressjsId = parseInt(this._targetElement[0].getAttribute('data-progressjs'));
|
||||
|
||||
|
||||
for (var i = 0, elmsLength = this._targetElement.length; i < elmsLength; i++) {
|
||||
var currentElement = this._targetElement[i];
|
||||
var percentElement = _getPercentElement(currentElement);
|
||||
|
@ -300,7 +300,7 @@
|
|||
return;
|
||||
|
||||
var existingPercent = parseInt(percentElement.style.width.replace('%', ''));
|
||||
|
||||
|
||||
var timeoutSec = 1;
|
||||
if (existingPercent < 100) {
|
||||
_setPercentFor.call(this, currentElement, 100);
|
||||
|
@ -412,7 +412,7 @@
|
|||
} else if (typeof (targetElm) === 'string') {
|
||||
//select the target element with query selector
|
||||
var targetElement = document.querySelectorAll(targetElm);
|
||||
|
||||
|
||||
if (targetElement) {
|
||||
return new ProgressJs(targetElement);
|
||||
} else {
|
||||
|
|
432
vendors/ckeditor-plugins/plain/plugin.js
vendored
432
vendors/ckeditor-plugins/plain/plugin.js
vendored
|
@ -1,216 +1,216 @@
|
|||
|
||||
(function() {
|
||||
|
||||
var
|
||||
selectRange = function (el, start, end) {
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
if (end === undefined) {
|
||||
end = start;
|
||||
}
|
||||
if('selectionStart' in el) {
|
||||
el.selectionStart = start;
|
||||
el.selectionEnd = end;
|
||||
} else if(el.setSelectionRange) {
|
||||
el.setSelectionRange(start, end);
|
||||
} else if(el.createTextRange) {
|
||||
var range = el.createTextRange();
|
||||
range.collapse(true);
|
||||
range.moveEnd('character', end);
|
||||
range.moveStart('character', start);
|
||||
range.select();
|
||||
}
|
||||
},
|
||||
toTop = function (el) {
|
||||
selectRange(el, 0);
|
||||
if (el) {
|
||||
el.scrollTop = 0;
|
||||
}
|
||||
},
|
||||
simplePlainToHtml = function (sPlain) {
|
||||
return sPlain
|
||||
.replace(/&/g, '&')
|
||||
.replace(/>/g, '>').replace(/</g, '<')
|
||||
.replace(/[\-_~]{10,}/g, '<hr />')
|
||||
.replace(/\n/g, '<br />')
|
||||
.replace(/ /g, ' ')
|
||||
;
|
||||
},
|
||||
simpleHtmlToPlain = function (sHtml) {
|
||||
|
||||
var sText = sHtml
|
||||
.replace(/[\s]+/gm, ' ')
|
||||
.replace(/<br[^>]*>/gmi, '\n')
|
||||
.replace(/<\/h[\d]>/gi, '\n')
|
||||
.replace(/<\/p>/gi, '\n\n')
|
||||
.replace(/<\/li>/gi, '\n')
|
||||
.replace(/<\/td>/gi, '\n')
|
||||
.replace(/<\/tr>/gi, '\n')
|
||||
.replace(/<\/div>/gi, '\n')
|
||||
.replace(/<blockquote[^>]*>/gmi, '\n')
|
||||
.replace(/<\/blockquote>/gi, '\n')
|
||||
.replace(/<hr[^>]*>/gmi, '\n_______________________________\n\n')
|
||||
.replace(/ /gi, ' ')
|
||||
.replace(/"/gi, '"')
|
||||
.replace(/<[^>]*>/gm, '')
|
||||
;
|
||||
|
||||
sText = $('<div></div>').html(sText).text();
|
||||
|
||||
sText = sText
|
||||
.replace(/\n[ \t]+/gm, '\n')
|
||||
.replace(/[\n]{3,}/gm, '\n\n')
|
||||
.replace(/>/gi, '>')
|
||||
.replace(/</gi, '<')
|
||||
.replace(/&/gi, '&')
|
||||
;
|
||||
|
||||
return sText;
|
||||
}
|
||||
;
|
||||
|
||||
CKEDITOR.plugins.add('plain', {
|
||||
lang: '',
|
||||
icons: 'plain',
|
||||
hidpi: true,
|
||||
init: function(editor)
|
||||
{
|
||||
if (editor.elementMode === CKEDITOR.ELEMENT_MODE_INLINE) {
|
||||
return;
|
||||
}
|
||||
|
||||
editor.__textUtils = {
|
||||
plainToHtml: function(data) {
|
||||
return window.rainloop_Utils_plainToHtml ?
|
||||
window.rainloop_Utils_plainToHtml(data, true) : simplePlainToHtml(data);
|
||||
},
|
||||
htmlToPlain: function(data) {
|
||||
return window.rainloop_Utils_htmlToPlain ?
|
||||
window.rainloop_Utils_htmlToPlain(data, true) : simpleHtmlToPlain(data);
|
||||
}
|
||||
};
|
||||
|
||||
var plain = CKEDITOR.plugins.plain;
|
||||
editor.addMode('plain', function(callback) {
|
||||
|
||||
var
|
||||
contentsSpace = editor.ui.space('contents'),
|
||||
textarea = contentsSpace.getDocument().createElement('textarea')
|
||||
;
|
||||
|
||||
textarea.setStyles(
|
||||
CKEDITOR.tools.extend({
|
||||
width: CKEDITOR.env.ie7Compat ? '99%' : '100%',
|
||||
height: '100%',
|
||||
resize: 'none',
|
||||
outline: 'none',
|
||||
'text-align': 'left'
|
||||
},
|
||||
CKEDITOR.tools.cssVendorPrefix('tab-size', 4)))
|
||||
;
|
||||
|
||||
textarea.setAttribute('dir', 'ltr');
|
||||
textarea.addClass('cke_plain');
|
||||
|
||||
CKEDITOR.plugins.clipboard.preventDefaultDropOnElement(textarea);
|
||||
|
||||
contentsSpace.append(textarea);
|
||||
|
||||
var editable = editor.editable(new plainEditable(editor, textarea));
|
||||
|
||||
editable.setData(editor.getData(1));
|
||||
editor.__plain = editable;
|
||||
editor.__textarea = textarea.$;
|
||||
|
||||
if (CKEDITOR.env.ie) {
|
||||
editable.attachListener(editor, 'resize', onResize, editable);
|
||||
editable.attachListener(CKEDITOR.document.getWindow(), 'resize', onResize, editable);
|
||||
CKEDITOR.tools.setTimeout(onResize, 0, editable);
|
||||
}
|
||||
|
||||
editor.fire('ariaWidget', this);
|
||||
callback();
|
||||
});
|
||||
|
||||
editor.addCommand('plain', plain.commands.plain);
|
||||
|
||||
if (editor.ui.addButton) {
|
||||
editor.ui.addButton('plain', {
|
||||
label: window.rl && window.rl.i18n ? window.rl.i18n('EDITOR/TEXT_SWITCHER_PLAINT_TEXT') : 'Plain',
|
||||
command: 'plain',
|
||||
toolbar: 'spec,10'
|
||||
});
|
||||
}
|
||||
|
||||
editor.on('mode', function() {
|
||||
editor.getCommand('plain').setState(editor.mode === 'plain' ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF);
|
||||
editor.editable().addClass('cke_enable_context_menu');
|
||||
|
||||
editor.focus();
|
||||
|
||||
if (editor.mode === 'plain') {
|
||||
toTop(editor.__textarea);
|
||||
}
|
||||
});
|
||||
|
||||
function onResize() {
|
||||
this.hide();
|
||||
this.setStyle('height', this.getParent().$.clientHeight + 'px');
|
||||
this.setStyle('width', this.getParent().$.clientWidth + 'px');
|
||||
this.show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var plainEditable = CKEDITOR.tools.createClass({
|
||||
base: CKEDITOR.editable,
|
||||
proto: {
|
||||
setData: function(data) {
|
||||
this.setValue(this.editor.__textUtils.htmlToPlain(data));
|
||||
this.editor.fire('dataReady');
|
||||
},
|
||||
setRawData: function(data) {
|
||||
this.setValue(data);
|
||||
this.editor.fire('dataReady');
|
||||
},
|
||||
getData: function() {
|
||||
return this.editor.__textUtils.plainToHtml(this.getValue());
|
||||
},
|
||||
getRawData: function() {
|
||||
return this.getValue();
|
||||
},
|
||||
insertHtml: function() {},
|
||||
insertElement: function() {},
|
||||
insertText: function() {},
|
||||
setReadOnly: function( isReadOnly ) {
|
||||
this[(isReadOnly ? 'set' : 'remove') + 'Attribute' ]('readOnly', 'readonly');
|
||||
},
|
||||
detach: function() {
|
||||
plainEditable.baseProto.detach.call( this );
|
||||
this.clearCustomData();
|
||||
this.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
CKEDITOR.plugins.plain = {
|
||||
commands: {
|
||||
plain: {
|
||||
modes: {
|
||||
wysiwyg: 1, plain: 1
|
||||
},
|
||||
editorFocus: true,
|
||||
readOnly: false,
|
||||
exec: function(editor) {
|
||||
if (editor.mode === 'wysiwyg') {
|
||||
editor.fire('saveSnapshot');
|
||||
}
|
||||
editor.getCommand('plain').setState(CKEDITOR.TRISTATE_DISABLED);
|
||||
editor.setMode(editor.mode === 'plain' ? 'wysiwyg' : 'plain');
|
||||
},
|
||||
canUndo: false
|
||||
}
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
||||
(function() {
|
||||
|
||||
var
|
||||
selectRange = function (el, start, end) {
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
if (end === undefined) {
|
||||
end = start;
|
||||
}
|
||||
if('selectionStart' in el) {
|
||||
el.selectionStart = start;
|
||||
el.selectionEnd = end;
|
||||
} else if(el.setSelectionRange) {
|
||||
el.setSelectionRange(start, end);
|
||||
} else if(el.createTextRange) {
|
||||
var range = el.createTextRange();
|
||||
range.collapse(true);
|
||||
range.moveEnd('character', end);
|
||||
range.moveStart('character', start);
|
||||
range.select();
|
||||
}
|
||||
},
|
||||
toTop = function (el) {
|
||||
selectRange(el, 0);
|
||||
if (el) {
|
||||
el.scrollTop = 0;
|
||||
}
|
||||
},
|
||||
simplePlainToHtml = function (sPlain) {
|
||||
return sPlain
|
||||
.replace(/&/g, '&')
|
||||
.replace(/>/g, '>').replace(/</g, '<')
|
||||
.replace(/[\-_~]{10,}/g, '<hr />')
|
||||
.replace(/\n/g, '<br />')
|
||||
.replace(/ /g, ' ')
|
||||
;
|
||||
},
|
||||
simpleHtmlToPlain = function (sHtml) {
|
||||
|
||||
var sText = sHtml
|
||||
.replace(/[\s]+/gm, ' ')
|
||||
.replace(/<br[^>]*>/gmi, '\n')
|
||||
.replace(/<\/h[\d]>/gi, '\n')
|
||||
.replace(/<\/p>/gi, '\n\n')
|
||||
.replace(/<\/li>/gi, '\n')
|
||||
.replace(/<\/td>/gi, '\n')
|
||||
.replace(/<\/tr>/gi, '\n')
|
||||
.replace(/<\/div>/gi, '\n')
|
||||
.replace(/<blockquote[^>]*>/gmi, '\n')
|
||||
.replace(/<\/blockquote>/gi, '\n')
|
||||
.replace(/<hr[^>]*>/gmi, '\n_______________________________\n\n')
|
||||
.replace(/ /gi, ' ')
|
||||
.replace(/"/gi, '"')
|
||||
.replace(/<[^>]*>/gm, '')
|
||||
;
|
||||
|
||||
sText = $('<div></div>').html(sText).text();
|
||||
|
||||
sText = sText
|
||||
.replace(/\n[ \t]+/gm, '\n')
|
||||
.replace(/[\n]{3,}/gm, '\n\n')
|
||||
.replace(/>/gi, '>')
|
||||
.replace(/</gi, '<')
|
||||
.replace(/&/gi, '&')
|
||||
;
|
||||
|
||||
return sText;
|
||||
}
|
||||
;
|
||||
|
||||
CKEDITOR.plugins.add('plain', {
|
||||
lang: '',
|
||||
icons: 'plain',
|
||||
hidpi: true,
|
||||
init: function(editor)
|
||||
{
|
||||
if (editor.elementMode === CKEDITOR.ELEMENT_MODE_INLINE) {
|
||||
return;
|
||||
}
|
||||
|
||||
editor.__textUtils = {
|
||||
plainToHtml: function(data) {
|
||||
return window.rainloop_Utils_plainToHtml ?
|
||||
window.rainloop_Utils_plainToHtml(data, true) : simplePlainToHtml(data);
|
||||
},
|
||||
htmlToPlain: function(data) {
|
||||
return window.rainloop_Utils_htmlToPlain ?
|
||||
window.rainloop_Utils_htmlToPlain(data, true) : simpleHtmlToPlain(data);
|
||||
}
|
||||
};
|
||||
|
||||
var plain = CKEDITOR.plugins.plain;
|
||||
editor.addMode('plain', function(callback) {
|
||||
|
||||
var
|
||||
contentsSpace = editor.ui.space('contents'),
|
||||
textarea = contentsSpace.getDocument().createElement('textarea')
|
||||
;
|
||||
|
||||
textarea.setStyles(
|
||||
CKEDITOR.tools.extend({
|
||||
width: CKEDITOR.env.ie7Compat ? '99%' : '100%',
|
||||
height: '100%',
|
||||
resize: 'none',
|
||||
outline: 'none',
|
||||
'text-align': 'left'
|
||||
},
|
||||
CKEDITOR.tools.cssVendorPrefix('tab-size', 4)))
|
||||
;
|
||||
|
||||
textarea.setAttribute('dir', 'ltr');
|
||||
textarea.addClass('cke_plain');
|
||||
|
||||
CKEDITOR.plugins.clipboard.preventDefaultDropOnElement(textarea);
|
||||
|
||||
contentsSpace.append(textarea);
|
||||
|
||||
var editable = editor.editable(new plainEditable(editor, textarea));
|
||||
|
||||
editable.setData(editor.getData(1));
|
||||
editor.__plain = editable;
|
||||
editor.__textarea = textarea.$;
|
||||
|
||||
if (CKEDITOR.env.ie) {
|
||||
editable.attachListener(editor, 'resize', onResize, editable);
|
||||
editable.attachListener(CKEDITOR.document.getWindow(), 'resize', onResize, editable);
|
||||
CKEDITOR.tools.setTimeout(onResize, 0, editable);
|
||||
}
|
||||
|
||||
editor.fire('ariaWidget', this);
|
||||
callback();
|
||||
});
|
||||
|
||||
editor.addCommand('plain', plain.commands.plain);
|
||||
|
||||
if (editor.ui.addButton) {
|
||||
editor.ui.addButton('plain', {
|
||||
label: window.rl && window.rl.i18n ? window.rl.i18n('EDITOR/TEXT_SWITCHER_PLAINT_TEXT') : 'Plain',
|
||||
command: 'plain',
|
||||
toolbar: 'spec,10'
|
||||
});
|
||||
}
|
||||
|
||||
editor.on('mode', function() {
|
||||
editor.getCommand('plain').setState(editor.mode === 'plain' ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF);
|
||||
editor.editable().addClass('cke_enable_context_menu');
|
||||
|
||||
editor.focus();
|
||||
|
||||
if (editor.mode === 'plain') {
|
||||
toTop(editor.__textarea);
|
||||
}
|
||||
});
|
||||
|
||||
function onResize() {
|
||||
this.hide();
|
||||
this.setStyle('height', this.getParent().$.clientHeight + 'px');
|
||||
this.setStyle('width', this.getParent().$.clientWidth + 'px');
|
||||
this.show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var plainEditable = CKEDITOR.tools.createClass({
|
||||
base: CKEDITOR.editable,
|
||||
proto: {
|
||||
setData: function(data) {
|
||||
this.setValue(this.editor.__textUtils.htmlToPlain(data));
|
||||
this.editor.fire('dataReady');
|
||||
},
|
||||
setRawData: function(data) {
|
||||
this.setValue(data);
|
||||
this.editor.fire('dataReady');
|
||||
},
|
||||
getData: function() {
|
||||
return this.editor.__textUtils.plainToHtml(this.getValue());
|
||||
},
|
||||
getRawData: function() {
|
||||
return this.getValue();
|
||||
},
|
||||
insertHtml: function() {},
|
||||
insertElement: function() {},
|
||||
insertText: function() {},
|
||||
setReadOnly: function( isReadOnly ) {
|
||||
this[(isReadOnly ? 'set' : 'remove') + 'Attribute' ]('readOnly', 'readonly');
|
||||
},
|
||||
detach: function() {
|
||||
plainEditable.baseProto.detach.call( this );
|
||||
this.clearCustomData();
|
||||
this.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
CKEDITOR.plugins.plain = {
|
||||
commands: {
|
||||
plain: {
|
||||
modes: {
|
||||
wysiwyg: 1, plain: 1
|
||||
},
|
||||
editorFocus: true,
|
||||
readOnly: false,
|
||||
exec: function(editor) {
|
||||
if (editor.mode === 'wysiwyg') {
|
||||
editor.fire('saveSnapshot');
|
||||
}
|
||||
editor.getCommand('plain').setState(CKEDITOR.TRISTATE_DISABLED);
|
||||
editor.setMode(editor.mode === 'plain' ? 'wysiwyg' : 'plain');
|
||||
},
|
||||
canUndo: false
|
||||
}
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
|
282
vendors/ckeditor-plugins/signature/plugin.js
vendored
282
vendors/ckeditor-plugins/signature/plugin.js
vendored
|
@ -1,141 +1,141 @@
|
|||
|
||||
(function(CKEDITOR, $, undefined) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var rl_signature_replacer = function(editor, text, signature, isHtml, insertBefore) {
|
||||
|
||||
var
|
||||
skipInsert = false,
|
||||
isEmptyText = false,
|
||||
newLine = (isHtml ? '<br />' : "\n"),
|
||||
clearHtmlLine = function(html) {
|
||||
return $.trim(editor.__textUtils.htmlToPlain(html));
|
||||
};
|
||||
|
||||
isEmptyText = '' === $.trim(text);
|
||||
if (!isEmptyText && isHtml)
|
||||
{
|
||||
isEmptyText = '' === clearHtmlLine(text);
|
||||
}
|
||||
|
||||
if (editor.__previos_signature && !isEmptyText)
|
||||
{
|
||||
if (isHtml && !editor.__previos_signature_is_html)
|
||||
{
|
||||
editor.__previos_signature = editor.__textUtils.plainToHtml(editor.__previos_signature);
|
||||
editor.__previos_signature_is_html = true;
|
||||
}
|
||||
else if (!isHtml && editor.__previos_signature_is_html)
|
||||
{
|
||||
editor.__previos_signature = editor.__textUtils.htmlToPlain(editor.__previos_signature);
|
||||
editor.__previos_signature_is_html = false;
|
||||
}
|
||||
|
||||
skipInsert = false;
|
||||
if (isHtml)
|
||||
{
|
||||
var clearSig = clearHtmlLine(editor.__previos_signature);
|
||||
text = text.replace(/<signature>([\s\S]*)<\/signature>/igm, function(all){
|
||||
var c = clearSig === clearHtmlLine(all);
|
||||
if (!c) {
|
||||
skipInsert = true;
|
||||
}
|
||||
return c ? '' : all;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var textLen = text.length;
|
||||
text = text
|
||||
.replace('' + editor.__previos_signature, '')
|
||||
.replace('' + editor.__previos_signature, '');
|
||||
|
||||
if (textLen === text.length)
|
||||
{
|
||||
skipInsert = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!skipInsert)
|
||||
{
|
||||
signature = newLine + newLine + (isHtml ? '<signature>' : '') + signature + (isHtml ? '</signature>' : '');
|
||||
|
||||
text = insertBefore ? signature + text : text + signature;
|
||||
|
||||
if (10 < signature.length)
|
||||
{
|
||||
editor.__previos_signature = signature;
|
||||
editor.__previos_signature_is_html = isHtml;
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
};
|
||||
|
||||
CKEDITOR.plugins.add('signature', {
|
||||
init: function(editor) {
|
||||
editor.addCommand('insertSignature', {
|
||||
modes: {wysiwyg: 1, plain: 1},
|
||||
exec: function(editor, cfg) {
|
||||
|
||||
if (cfg && cfg.clearCache)
|
||||
{
|
||||
editor.__previos_signature = undefined;
|
||||
editor.__previos_signature_is_html = undefined;
|
||||
return true;
|
||||
}
|
||||
|
||||
var
|
||||
bIsHtml = false,
|
||||
bInsertBefore = false,
|
||||
sSignature = '',
|
||||
sResultSignature = '';
|
||||
|
||||
if (cfg)
|
||||
{
|
||||
bIsHtml = undefined === cfg.isHtml ? false : !!cfg.isHtml;
|
||||
bInsertBefore = undefined === cfg.insertBefore ? false : !!cfg.insertBefore;
|
||||
sSignature = undefined === cfg.signature ? '' : cfg.signature;
|
||||
}
|
||||
|
||||
sResultSignature = sSignature;
|
||||
|
||||
try
|
||||
{
|
||||
if ('plain' === editor.mode && editor.__plain && editor.__textUtils)
|
||||
{
|
||||
if (editor.__textUtils && editor.__textUtils.htmlToPlain)
|
||||
{
|
||||
if (bIsHtml)
|
||||
{
|
||||
sResultSignature = editor.__textUtils.htmlToPlain(sResultSignature);
|
||||
}
|
||||
}
|
||||
|
||||
editor.__plain.setRawData(
|
||||
rl_signature_replacer(editor, editor.__plain.getRawData(), sResultSignature, false, bInsertBefore));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (editor.__textUtils && editor.__textUtils.plainToHtml)
|
||||
{
|
||||
if (!bIsHtml)
|
||||
{
|
||||
sResultSignature = editor.__textUtils.plainToHtml(sResultSignature);
|
||||
}
|
||||
}
|
||||
|
||||
editor.setData(
|
||||
rl_signature_replacer(editor, editor.getData(), sResultSignature, true, bInsertBefore));
|
||||
}
|
||||
}
|
||||
catch (e) {}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}(CKEDITOR, $));
|
||||
|
||||
(function(CKEDITOR, $, undefined) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var rl_signature_replacer = function(editor, text, signature, isHtml, insertBefore) {
|
||||
|
||||
var
|
||||
skipInsert = false,
|
||||
isEmptyText = false,
|
||||
newLine = (isHtml ? '<br />' : "\n"),
|
||||
clearHtmlLine = function(html) {
|
||||
return $.trim(editor.__textUtils.htmlToPlain(html));
|
||||
};
|
||||
|
||||
isEmptyText = '' === $.trim(text);
|
||||
if (!isEmptyText && isHtml)
|
||||
{
|
||||
isEmptyText = '' === clearHtmlLine(text);
|
||||
}
|
||||
|
||||
if (editor.__previos_signature && !isEmptyText)
|
||||
{
|
||||
if (isHtml && !editor.__previos_signature_is_html)
|
||||
{
|
||||
editor.__previos_signature = editor.__textUtils.plainToHtml(editor.__previos_signature);
|
||||
editor.__previos_signature_is_html = true;
|
||||
}
|
||||
else if (!isHtml && editor.__previos_signature_is_html)
|
||||
{
|
||||
editor.__previos_signature = editor.__textUtils.htmlToPlain(editor.__previos_signature);
|
||||
editor.__previos_signature_is_html = false;
|
||||
}
|
||||
|
||||
skipInsert = false;
|
||||
if (isHtml)
|
||||
{
|
||||
var clearSig = clearHtmlLine(editor.__previos_signature);
|
||||
text = text.replace(/<signature>([\s\S]*)<\/signature>/igm, function(all){
|
||||
var c = clearSig === clearHtmlLine(all);
|
||||
if (!c) {
|
||||
skipInsert = true;
|
||||
}
|
||||
return c ? '' : all;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var textLen = text.length;
|
||||
text = text
|
||||
.replace('' + editor.__previos_signature, '')
|
||||
.replace('' + editor.__previos_signature, '');
|
||||
|
||||
if (textLen === text.length)
|
||||
{
|
||||
skipInsert = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!skipInsert)
|
||||
{
|
||||
signature = newLine + newLine + (isHtml ? '<signature>' : '') + signature + (isHtml ? '</signature>' : '');
|
||||
|
||||
text = insertBefore ? signature + text : text + signature;
|
||||
|
||||
if (10 < signature.length)
|
||||
{
|
||||
editor.__previos_signature = signature;
|
||||
editor.__previos_signature_is_html = isHtml;
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
};
|
||||
|
||||
CKEDITOR.plugins.add('signature', {
|
||||
init: function(editor) {
|
||||
editor.addCommand('insertSignature', {
|
||||
modes: {wysiwyg: 1, plain: 1},
|
||||
exec: function(editor, cfg) {
|
||||
|
||||
if (cfg && cfg.clearCache)
|
||||
{
|
||||
editor.__previos_signature = undefined;
|
||||
editor.__previos_signature_is_html = undefined;
|
||||
return true;
|
||||
}
|
||||
|
||||
var
|
||||
bIsHtml = false,
|
||||
bInsertBefore = false,
|
||||
sSignature = '',
|
||||
sResultSignature = '';
|
||||
|
||||
if (cfg)
|
||||
{
|
||||
bIsHtml = undefined === cfg.isHtml ? false : !!cfg.isHtml;
|
||||
bInsertBefore = undefined === cfg.insertBefore ? false : !!cfg.insertBefore;
|
||||
sSignature = undefined === cfg.signature ? '' : cfg.signature;
|
||||
}
|
||||
|
||||
sResultSignature = sSignature;
|
||||
|
||||
try
|
||||
{
|
||||
if ('plain' === editor.mode && editor.__plain && editor.__textUtils)
|
||||
{
|
||||
if (editor.__textUtils && editor.__textUtils.htmlToPlain)
|
||||
{
|
||||
if (bIsHtml)
|
||||
{
|
||||
sResultSignature = editor.__textUtils.htmlToPlain(sResultSignature);
|
||||
}
|
||||
}
|
||||
|
||||
editor.__plain.setRawData(
|
||||
rl_signature_replacer(editor, editor.__plain.getRawData(), sResultSignature, false, bInsertBefore));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (editor.__textUtils && editor.__textUtils.plainToHtml)
|
||||
{
|
||||
if (!bIsHtml)
|
||||
{
|
||||
sResultSignature = editor.__textUtils.plainToHtml(sResultSignature);
|
||||
}
|
||||
}
|
||||
|
||||
editor.setData(
|
||||
rl_signature_replacer(editor, editor.getData(), sResultSignature, true, bInsertBefore));
|
||||
}
|
||||
}
|
||||
catch (e) {}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}(CKEDITOR, $));
|
||||
|
|
24
vendors/ckeditor/FIXES.txt
vendored
24
vendors/ckeditor/FIXES.txt
vendored
|
@ -1,12 +1,12 @@
|
|||
:(t=!!k[n],"br"!=n||!e.data("cke-eol")
|
||||
:(t=!k||!!k[n],"br"!=n||!e.data("cke-eol")
|
||||
|
||||
---
|
||||
|
||||
for(F=null;y&&!p[y.getName()][L.name];){
|
||||
for(F=null;y&&(!p||!p[y.getName()]||!p[y.getName()][L.name]);){
|
||||
|
||||
---
|
||||
|
||||
a.window.$.getSelection().removeAllRanges()
|
||||
a.window&&a.window.$&&a.window.$.getSelection().removeAllRanges()
|
||||
:(t=!!k[n],"br"!=n||!e.data("cke-eol")
|
||||
:(t=!k||!!k[n],"br"!=n||!e.data("cke-eol")
|
||||
|
||||
---
|
||||
|
||||
for(F=null;y&&!p[y.getName()][L.name];){
|
||||
for(F=null;y&&(!p||!p[y.getName()]||!p[y.getName()][L.name]);){
|
||||
|
||||
---
|
||||
|
||||
a.window.$.getSelection().removeAllRanges()
|
||||
a.window&&a.window.$&&a.window.$.getSelection().removeAllRanges()
|
||||
|
|
2
vendors/ckeditor/adapters/jquery.js
vendored
2
vendors/ckeditor/adapters/jquery.js
vendored
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or http://ckeditor.com/license
|
||||
*/
|
||||
|
|
102
vendors/ckeditor/build-config.js
vendored
102
vendors/ckeditor/build-config.js
vendored
|
@ -1,54 +1,54 @@
|
|||
/**
|
||||
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
|
||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file was added automatically by CKEditor builder.
|
||||
* You may re-use it at any time to build CKEditor again.
|
||||
*
|
||||
* If you would like to build CKEditor online again
|
||||
* (for example to upgrade), visit one the following links:
|
||||
*
|
||||
* (1) http://ckeditor.com/builder
|
||||
* Visit online builder to build CKEditor from scratch.
|
||||
*
|
||||
* (2) http://ckeditor.com/builder/9b9471acfb896c4f73b825ccf971b5bc
|
||||
* Visit online builder to build CKEditor, starting with the same setup as before.
|
||||
*
|
||||
* (3) http://ckeditor.com/builder/download/9b9471acfb896c4f73b825ccf971b5bc
|
||||
* Straight download link to the latest version of CKEditor (Optimized) with the same setup as before.
|
||||
*
|
||||
* NOTE:
|
||||
* This file is not used by CKEditor, you may remove it.
|
||||
* Changing this file will not change your CKEditor configuration.
|
||||
*/
|
||||
|
||||
var CKBUILDER_CONFIG = {
|
||||
skin: 'moono-lisa',
|
||||
preset: 'basic',
|
||||
ignore: [
|
||||
'.bender',
|
||||
'bender.js',
|
||||
'bender-err.log',
|
||||
'bender-out.log',
|
||||
'dev',
|
||||
'.DS_Store',
|
||||
'.editorconfig',
|
||||
'.gitattributes',
|
||||
'.gitignore',
|
||||
'gruntfile.js',
|
||||
'.idea',
|
||||
'.jscsrc',
|
||||
'.jshintignore',
|
||||
'.jshintrc',
|
||||
'less',
|
||||
'.mailmap',
|
||||
'node_modules',
|
||||
'package.json',
|
||||
'README.md',
|
||||
'tests'
|
||||
],
|
||||
/**
|
||||
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
|
||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file was added automatically by CKEditor builder.
|
||||
* You may re-use it at any time to build CKEditor again.
|
||||
*
|
||||
* If you would like to build CKEditor online again
|
||||
* (for example to upgrade), visit one the following links:
|
||||
*
|
||||
* (1) http://ckeditor.com/builder
|
||||
* Visit online builder to build CKEditor from scratch.
|
||||
*
|
||||
* (2) http://ckeditor.com/builder/9b9471acfb896c4f73b825ccf971b5bc
|
||||
* Visit online builder to build CKEditor, starting with the same setup as before.
|
||||
*
|
||||
* (3) http://ckeditor.com/builder/download/9b9471acfb896c4f73b825ccf971b5bc
|
||||
* Straight download link to the latest version of CKEditor (Optimized) with the same setup as before.
|
||||
*
|
||||
* NOTE:
|
||||
* This file is not used by CKEditor, you may remove it.
|
||||
* Changing this file will not change your CKEditor configuration.
|
||||
*/
|
||||
|
||||
var CKBUILDER_CONFIG = {
|
||||
skin: 'moono-lisa',
|
||||
preset: 'basic',
|
||||
ignore: [
|
||||
'.bender',
|
||||
'bender.js',
|
||||
'bender-err.log',
|
||||
'bender-out.log',
|
||||
'dev',
|
||||
'.DS_Store',
|
||||
'.editorconfig',
|
||||
'.gitattributes',
|
||||
'.gitignore',
|
||||
'gruntfile.js',
|
||||
'.idea',
|
||||
'.jscsrc',
|
||||
'.jshintignore',
|
||||
'.jshintrc',
|
||||
'less',
|
||||
'.mailmap',
|
||||
'node_modules',
|
||||
'package.json',
|
||||
'README.md',
|
||||
'tests'
|
||||
],
|
||||
plugins : {
|
||||
'about' : 1,
|
||||
'autolink' : 1,
|
||||
|
|
2
vendors/ckeditor/ckeditor.js
vendored
2
vendors/ckeditor/ckeditor.js
vendored
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or http://ckeditor.com/license
|
||||
*/
|
||||
|
|
2
vendors/ckeditor/ckeditor.orig.js
vendored
2
vendors/ckeditor/ckeditor.orig.js
vendored
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or http://ckeditor.com/license
|
||||
*/
|
||||
|
|
416
vendors/ckeditor/contents.css
vendored
416
vendors/ckeditor/contents.css
vendored
|
@ -1,208 +1,208 @@
|
|||
/*
|
||||
Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or http://ckeditor.com/license
|
||||
*/
|
||||
|
||||
body
|
||||
{
|
||||
/* Font */
|
||||
font-family: sans-serif, Arial, Verdana, "Trebuchet MS";
|
||||
font-size: 12px;
|
||||
|
||||
/* Text color */
|
||||
color: #333;
|
||||
|
||||
/* Remove the background color to make it transparent */
|
||||
background-color: #fff;
|
||||
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.cke_editable
|
||||
{
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
|
||||
/* Fix for missing scrollbars with RTL texts. (#10488) */
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
blockquote
|
||||
{
|
||||
font-style: italic;
|
||||
font-family: Georgia, Times, "Times New Roman", serif;
|
||||
padding: 2px 0;
|
||||
border-style: solid;
|
||||
border-color: #ccc;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
.cke_contents_ltr blockquote
|
||||
{
|
||||
padding-left: 20px;
|
||||
padding-right: 8px;
|
||||
border-left-width: 5px;
|
||||
}
|
||||
|
||||
.cke_contents_rtl blockquote
|
||||
{
|
||||
padding-left: 8px;
|
||||
padding-right: 20px;
|
||||
border-right-width: 5px;
|
||||
}
|
||||
|
||||
a
|
||||
{
|
||||
color: #0782C1;
|
||||
}
|
||||
|
||||
ol,ul,dl
|
||||
{
|
||||
/* IE7: reset rtl list margin. (#7334) */
|
||||
*margin-right: 0px;
|
||||
/* preserved spaces for list items with text direction other than the list. (#6249,#8049)*/
|
||||
padding: 0 40px;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6
|
||||
{
|
||||
font-weight: normal;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
hr
|
||||
{
|
||||
border: 0px;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
img.right
|
||||
{
|
||||
border: 1px solid #ccc;
|
||||
float: right;
|
||||
margin-left: 15px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
img.left
|
||||
{
|
||||
border: 1px solid #ccc;
|
||||
float: left;
|
||||
margin-right: 15px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
pre
|
||||
{
|
||||
white-space: pre-wrap; /* CSS 2.1 */
|
||||
word-wrap: break-word; /* IE7 */
|
||||
-moz-tab-size: 4;
|
||||
tab-size: 4;
|
||||
}
|
||||
|
||||
.marker
|
||||
{
|
||||
background-color: Yellow;
|
||||
}
|
||||
|
||||
span[lang]
|
||||
{
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
figure
|
||||
{
|
||||
text-align: center;
|
||||
border: solid 1px #ccc;
|
||||
border-radius: 2px;
|
||||
background: rgba(0,0,0,0.05);
|
||||
padding: 10px;
|
||||
margin: 10px 20px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
figure > figcaption
|
||||
{
|
||||
text-align: center;
|
||||
display: block; /* For IE8 */
|
||||
}
|
||||
|
||||
a > img {
|
||||
padding: 1px;
|
||||
margin: 1px;
|
||||
border: none;
|
||||
outline: 1px solid #0782C1;
|
||||
}
|
||||
|
||||
/* Widget Styles */
|
||||
.code-featured
|
||||
{
|
||||
border: 5px solid red;
|
||||
}
|
||||
|
||||
.math-featured
|
||||
{
|
||||
padding: 20px;
|
||||
box-shadow: 0 0 2px rgba(200, 0, 0, 1);
|
||||
background-color: rgba(255, 0, 0, 0.05);
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.image-clean
|
||||
{
|
||||
border: 0;
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.image-clean > figcaption
|
||||
{
|
||||
font-size: .9em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.image-grayscale
|
||||
{
|
||||
background-color: white;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.image-grayscale img, img.image-grayscale
|
||||
{
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
.embed-240p
|
||||
{
|
||||
max-width: 426px;
|
||||
max-height: 240px;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.embed-360p
|
||||
{
|
||||
max-width: 640px;
|
||||
max-height: 360px;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.embed-480p
|
||||
{
|
||||
max-width: 854px;
|
||||
max-height: 480px;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.embed-720p
|
||||
{
|
||||
max-width: 1280px;
|
||||
max-height: 720px;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.embed-1080p
|
||||
{
|
||||
max-width: 1920px;
|
||||
max-height: 1080px;
|
||||
margin:0 auto;
|
||||
}
|
||||
/*
|
||||
Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or http://ckeditor.com/license
|
||||
*/
|
||||
|
||||
body
|
||||
{
|
||||
/* Font */
|
||||
font-family: sans-serif, Arial, Verdana, "Trebuchet MS";
|
||||
font-size: 12px;
|
||||
|
||||
/* Text color */
|
||||
color: #333;
|
||||
|
||||
/* Remove the background color to make it transparent */
|
||||
background-color: #fff;
|
||||
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.cke_editable
|
||||
{
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
|
||||
/* Fix for missing scrollbars with RTL texts. (#10488) */
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
blockquote
|
||||
{
|
||||
font-style: italic;
|
||||
font-family: Georgia, Times, "Times New Roman", serif;
|
||||
padding: 2px 0;
|
||||
border-style: solid;
|
||||
border-color: #ccc;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
.cke_contents_ltr blockquote
|
||||
{
|
||||
padding-left: 20px;
|
||||
padding-right: 8px;
|
||||
border-left-width: 5px;
|
||||
}
|
||||
|
||||
.cke_contents_rtl blockquote
|
||||
{
|
||||
padding-left: 8px;
|
||||
padding-right: 20px;
|
||||
border-right-width: 5px;
|
||||
}
|
||||
|
||||
a
|
||||
{
|
||||
color: #0782C1;
|
||||
}
|
||||
|
||||
ol,ul,dl
|
||||
{
|
||||
/* IE7: reset rtl list margin. (#7334) */
|
||||
*margin-right: 0px;
|
||||
/* preserved spaces for list items with text direction other than the list. (#6249,#8049)*/
|
||||
padding: 0 40px;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6
|
||||
{
|
||||
font-weight: normal;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
hr
|
||||
{
|
||||
border: 0px;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
img.right
|
||||
{
|
||||
border: 1px solid #ccc;
|
||||
float: right;
|
||||
margin-left: 15px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
img.left
|
||||
{
|
||||
border: 1px solid #ccc;
|
||||
float: left;
|
||||
margin-right: 15px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
pre
|
||||
{
|
||||
white-space: pre-wrap; /* CSS 2.1 */
|
||||
word-wrap: break-word; /* IE7 */
|
||||
-moz-tab-size: 4;
|
||||
tab-size: 4;
|
||||
}
|
||||
|
||||
.marker
|
||||
{
|
||||
background-color: Yellow;
|
||||
}
|
||||
|
||||
span[lang]
|
||||
{
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
figure
|
||||
{
|
||||
text-align: center;
|
||||
border: solid 1px #ccc;
|
||||
border-radius: 2px;
|
||||
background: rgba(0,0,0,0.05);
|
||||
padding: 10px;
|
||||
margin: 10px 20px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
figure > figcaption
|
||||
{
|
||||
text-align: center;
|
||||
display: block; /* For IE8 */
|
||||
}
|
||||
|
||||
a > img {
|
||||
padding: 1px;
|
||||
margin: 1px;
|
||||
border: none;
|
||||
outline: 1px solid #0782C1;
|
||||
}
|
||||
|
||||
/* Widget Styles */
|
||||
.code-featured
|
||||
{
|
||||
border: 5px solid red;
|
||||
}
|
||||
|
||||
.math-featured
|
||||
{
|
||||
padding: 20px;
|
||||
box-shadow: 0 0 2px rgba(200, 0, 0, 1);
|
||||
background-color: rgba(255, 0, 0, 0.05);
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.image-clean
|
||||
{
|
||||
border: 0;
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.image-clean > figcaption
|
||||
{
|
||||
font-size: .9em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.image-grayscale
|
||||
{
|
||||
background-color: white;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.image-grayscale img, img.image-grayscale
|
||||
{
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
.embed-240p
|
||||
{
|
||||
max-width: 426px;
|
||||
max-height: 240px;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.embed-360p
|
||||
{
|
||||
max-width: 640px;
|
||||
max-height: 360px;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.embed-480p
|
||||
{
|
||||
max-width: 854px;
|
||||
max-height: 480px;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.embed-720p
|
||||
{
|
||||
max-width: 1280px;
|
||||
max-height: 720px;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.embed-1080p
|
||||
{
|
||||
max-width: 1920px;
|
||||
max-height: 1080px;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
|
6
vendors/ckeditor/lang/af.js
vendored
6
vendors/ckeditor/lang/af.js
vendored
File diff suppressed because one or more lines are too long
247
vendors/ckeditor/lang/ar.js
vendored
247
vendors/ckeditor/lang/ar.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/az.js
vendored
6
vendors/ckeditor/lang/az.js
vendored
File diff suppressed because one or more lines are too long
14
vendors/ckeditor/lang/bg.js
vendored
14
vendors/ckeditor/lang/bg.js
vendored
File diff suppressed because one or more lines are too long
22
vendors/ckeditor/lang/bn.js
vendored
22
vendors/ckeditor/lang/bn.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/bs.js
vendored
6
vendors/ckeditor/lang/bs.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/ca.js
vendored
6
vendors/ckeditor/lang/ca.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/cs.js
vendored
6
vendors/ckeditor/lang/cs.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/cy.js
vendored
6
vendors/ckeditor/lang/cy.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/da.js
vendored
6
vendors/ckeditor/lang/da.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/de-ch.js
vendored
6
vendors/ckeditor/lang/de-ch.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/de.js
vendored
6
vendors/ckeditor/lang/de.js
vendored
File diff suppressed because one or more lines are too long
149
vendors/ckeditor/lang/el.js
vendored
149
vendors/ckeditor/lang/el.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/en-au.js
vendored
6
vendors/ckeditor/lang/en-au.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/en-ca.js
vendored
6
vendors/ckeditor/lang/en-ca.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/en-gb.js
vendored
6
vendors/ckeditor/lang/en-gb.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/en.js
vendored
6
vendors/ckeditor/lang/en.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/eo.js
vendored
6
vendors/ckeditor/lang/eo.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/es.js
vendored
6
vendors/ckeditor/lang/es.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/et.js
vendored
6
vendors/ckeditor/lang/et.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/eu.js
vendored
6
vendors/ckeditor/lang/eu.js
vendored
File diff suppressed because one or more lines are too long
170
vendors/ckeditor/lang/fa.js
vendored
170
vendors/ckeditor/lang/fa.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/fi.js
vendored
6
vendors/ckeditor/lang/fi.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/fo.js
vendored
6
vendors/ckeditor/lang/fo.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/fr-ca.js
vendored
6
vendors/ckeditor/lang/fr-ca.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/fr.js
vendored
6
vendors/ckeditor/lang/fr.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/gl.js
vendored
6
vendors/ckeditor/lang/gl.js
vendored
File diff suppressed because one or more lines are too long
39
vendors/ckeditor/lang/gu.js
vendored
39
vendors/ckeditor/lang/gu.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/he.js
vendored
6
vendors/ckeditor/lang/he.js
vendored
File diff suppressed because one or more lines are too long
45
vendors/ckeditor/lang/hi.js
vendored
45
vendors/ckeditor/lang/hi.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/hr.js
vendored
6
vendors/ckeditor/lang/hr.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/hu.js
vendored
6
vendors/ckeditor/lang/hu.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/id.js
vendored
6
vendors/ckeditor/lang/id.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/is.js
vendored
6
vendors/ckeditor/lang/is.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/it.js
vendored
6
vendors/ckeditor/lang/it.js
vendored
File diff suppressed because one or more lines are too long
76
vendors/ckeditor/lang/ja.js
vendored
76
vendors/ckeditor/lang/ja.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/ka.js
vendored
6
vendors/ckeditor/lang/ka.js
vendored
File diff suppressed because one or more lines are too long
127
vendors/ckeditor/lang/km.js
vendored
127
vendors/ckeditor/lang/km.js
vendored
File diff suppressed because one or more lines are too long
85
vendors/ckeditor/lang/ko.js
vendored
85
vendors/ckeditor/lang/ko.js
vendored
File diff suppressed because one or more lines are too long
107
vendors/ckeditor/lang/ku.js
vendored
107
vendors/ckeditor/lang/ku.js
vendored
File diff suppressed because one or more lines are too long
39
vendors/ckeditor/lang/lt.js
vendored
39
vendors/ckeditor/lang/lt.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/lv.js
vendored
6
vendors/ckeditor/lang/lv.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/mk.js
vendored
6
vendors/ckeditor/lang/mk.js
vendored
File diff suppressed because one or more lines are too long
169
vendors/ckeditor/lang/mn.js
vendored
169
vendors/ckeditor/lang/mn.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/ms.js
vendored
6
vendors/ckeditor/lang/ms.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/nb.js
vendored
6
vendors/ckeditor/lang/nb.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/nl.js
vendored
6
vendors/ckeditor/lang/nl.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/no.js
vendored
6
vendors/ckeditor/lang/no.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/oc.js
vendored
6
vendors/ckeditor/lang/oc.js
vendored
File diff suppressed because one or more lines are too long
69
vendors/ckeditor/lang/pl.js
vendored
69
vendors/ckeditor/lang/pl.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/pt-br.js
vendored
6
vendors/ckeditor/lang/pt-br.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/pt.js
vendored
6
vendors/ckeditor/lang/pt.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/ro.js
vendored
6
vendors/ckeditor/lang/ro.js
vendored
File diff suppressed because one or more lines are too long
25
vendors/ckeditor/lang/ru.js
vendored
25
vendors/ckeditor/lang/ru.js
vendored
File diff suppressed because one or more lines are too long
62
vendors/ckeditor/lang/si.js
vendored
62
vendors/ckeditor/lang/si.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/sk.js
vendored
6
vendors/ckeditor/lang/sk.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/sl.js
vendored
6
vendors/ckeditor/lang/sl.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/sq.js
vendored
6
vendors/ckeditor/lang/sq.js
vendored
File diff suppressed because one or more lines are too long
6
vendors/ckeditor/lang/sr-latn.js
vendored
6
vendors/ckeditor/lang/sr-latn.js
vendored
File diff suppressed because one or more lines are too long
12
vendors/ckeditor/lang/sr.js
vendored
12
vendors/ckeditor/lang/sr.js
vendored
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue