mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-31 13:09:21 +03:00
Merge branch 'master' into addressbook
# Conflicts: # snappymail/v/0.0.0/app/templates/Views/User/PopupsContacts.html
This commit is contained in:
commit
f46e996570
138 changed files with 2587 additions and 1016 deletions
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use \RainLoop\Exceptions\ClientException;
|
||||
|
||||
class ChangePasswordPoppassdPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
class ChangePasswordFroxlorPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
const
|
||||
NAME = 'Change Password Froxlor',
|
||||
|
|
|
|||
68
plugins/change-password-hestia/driver.php
Normal file
68
plugins/change-password-hestia/driver.php
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
class ChangePasswordHestiaDriver
|
||||
{
|
||||
const
|
||||
NAME = 'Hestia',
|
||||
DESCRIPTION = 'Change passwords in Hestia.';
|
||||
|
||||
/**
|
||||
* @var \RainLoop\Config\Plugin
|
||||
*/
|
||||
private $oConfig = null;
|
||||
|
||||
/**
|
||||
* @var \MailSo\Log\Logger
|
||||
*/
|
||||
protected $oLogger = null;
|
||||
|
||||
function __construct(\RainLoop\Config\Plugin $oConfig, \MailSo\Log\Logger $oLogger)
|
||||
{
|
||||
$this->oConfig = $oConfig;
|
||||
$this->oLogger = $oLogger;
|
||||
}
|
||||
|
||||
public static function isSupported() : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function configMapping() : array
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('hestia_host')->SetLabel('Hestia Host')
|
||||
->SetDefaultValue('')
|
||||
->SetDescription('Ex: localhost or domain.com'),
|
||||
\RainLoop\Plugins\Property::NewInstance('hestia_port')->SetLabel('Hestia Port')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::INT)
|
||||
->SetDefaultValue(8083),
|
||||
\RainLoop\Plugins\Property::NewInstance('hestia_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('*')
|
||||
);
|
||||
}
|
||||
|
||||
public function ChangePassword(\RainLoop\Model\Account $oAccount, string $sPrevPassword, string $sNewPassword) : bool
|
||||
{
|
||||
if (!\RainLoop\Plugins\Helper::ValidateWildcardValues($oAccount->Email(), $this->oConfig->Get('plugin', 'hestia_allowed_emails', ''))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sHost = $this->oConfig->Get('plugin', 'hestia_login');
|
||||
$sPort = $this->oConfig->Get('plugin', 'hestia_port');
|
||||
|
||||
$HTTP = \SnappyMail\HTTP\Request::factory();
|
||||
$postvars = array(
|
||||
'email' => $oAccount->Email(),
|
||||
'password' => $sPrevPassword,
|
||||
'new' => $sNewPassword,
|
||||
);
|
||||
$cRequest = $HTTP->doRequest('POST','https://'.$sHost.':'.$sPort.'/reset/mail/',http_build_query($postvars));
|
||||
if($cRequest -> body == '==ok=='){
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
plugins/change-password-hestia/index.php
Normal file
20
plugins/change-password-hestia/index.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
use \RainLoop\Exceptions\ClientException;
|
||||
|
||||
class ChangePasswordHestiaPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
const
|
||||
NAME = 'Change Password Hestia',
|
||||
AUTHOR = 'Jaap Marcus',
|
||||
VERSION = '1.0',
|
||||
RELEASE = '2022-06-02',
|
||||
REQUIRED = '2.16.3',
|
||||
CATEGORY = 'Security',
|
||||
DESCRIPTION = 'Extension to allow users to change their passwords through HestiaCP';
|
||||
|
||||
public function Supported() : string
|
||||
{
|
||||
return 'Use Change Password plugin';
|
||||
}
|
||||
}
|
||||
|
|
@ -160,8 +160,7 @@ class ChangePasswordPlugin extends \RainLoop\Plugins\AbstractPlugin
|
|||
$bResult = false;
|
||||
$oConfig = $this->Config();
|
||||
foreach ($this->getSupportedDrivers() as $name => $class) {
|
||||
$sFoundedValue = '';
|
||||
if (\RainLoop\Plugins\Helper::ValidateWildcardValues($oAccount->Email(), $oConfig->Get('plugin', "driver_{$name}_allowed_emails"), $sFoundedValue)) {
|
||||
if (\RainLoop\Plugins\Helper::ValidateWildcardValues($oAccount->Email(), $oConfig->Get('plugin', "driver_{$name}_allowed_emails"))) {
|
||||
$name = $class::NAME;
|
||||
$oLogger = $oActions->Logger();
|
||||
try
|
||||
|
|
|
|||
22
plugins/ldap-login-mapping/LICENSE
Normal file
22
plugins/ldap-login-mapping/LICENSE
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 RainLoop Team
|
||||
Copyright (c) 2018 <ludovic.pouzenc@mines-albi.fr>
|
||||
Copyright (c) 2022 <zephone@protonmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
1
plugins/ldap-login-mapping/README
Normal file
1
plugins/ldap-login-mapping/README
Normal file
|
|
@ -0,0 +1 @@
|
|||
Plugin which allows you to set up LDAP username by email address (when IMAP/SMTP requires it)
|
||||
1
plugins/ldap-login-mapping/VERSION
Normal file
1
plugins/ldap-login-mapping/VERSION
Normal file
|
|
@ -0,0 +1 @@
|
|||
2.0
|
||||
253
plugins/ldap-login-mapping/index.php
Normal file
253
plugins/ldap-login-mapping/index.php
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
<?php
|
||||
|
||||
use \MailSo\Log\Enumerations\Type;
|
||||
use \RainLoop\Enumerations\PluginPropertyType;
|
||||
use \RainLoop\Plugins\AbstractPlugin;
|
||||
use RainLoop\Plugins\Property;
|
||||
|
||||
class LDAPLoginMappingPlugin extends AbstractPlugin
|
||||
{
|
||||
const
|
||||
NAME = 'LDAP login mapping',
|
||||
VERSION = '2.0',
|
||||
AUTHOR = 'RainLoop Team, Ludovic Pouzenc<ludovic@pouzenc.fr>, ZephOne<zephone@protonmail.com>',
|
||||
RELEASE = '2022-07-13',
|
||||
REQUIRED = '2.16.3',
|
||||
CATEGORY = 'Login',
|
||||
DESCRIPTION = 'Enable custom mapping using ldap field';
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $aDomains = array();
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sSearchDomain = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sHostName = '127.0.0.1';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $iHostPort = 389;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sUsersDn = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sObjectClass = 'inetOrgPerson';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sLoginField = 'uid';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sEmailField = 'mail';
|
||||
|
||||
/**
|
||||
* @var \MailSo\Log\Logger
|
||||
*/
|
||||
private $oLogger = null;
|
||||
|
||||
public function Init(): void
|
||||
{
|
||||
$this->addHook('login.credentials', 'FilterLoginСredentials');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function Supported(): string
|
||||
{
|
||||
if (!\function_exists('ldap_connect'))
|
||||
{
|
||||
return 'The LDAP PHP extension must be installed to use this plugin';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sEmail
|
||||
* @param string $sLogin
|
||||
* @param string $sPassword
|
||||
*
|
||||
* @throws \RainLoop\Exceptions\ClientException
|
||||
*/
|
||||
public function FilterLoginСredentials(&$sEmail, &$sLogin, &$sPassword)
|
||||
{
|
||||
$this->oLogger = \MailSo\Log\Logger::SingletonInstance();
|
||||
|
||||
$this->aDomains = explode(',', $this->Config()->Get('plugin', 'domains', ''));
|
||||
$this->sSearchDomain = trim($this->Config()->Get('plugin', 'search_domain', ''));
|
||||
$this->sHostName = trim($this->Config()->Get('plugin', 'hostname', ''));
|
||||
$this->iHostPort = (int) $this->Config()->Get('plugin', 'port', 389);
|
||||
$this->sUsersDn = trim($this->Config()->Get('plugin', 'users_dn', ''));
|
||||
$this->sObjectClass = trim($this->Config()->Get('plugin', 'object_class', ''));
|
||||
$this->sLoginField = trim($this->Config()->Get('plugin', 'login_field', ''));
|
||||
$this->sEmailField = trim($this->Config()->Get('plugin', 'mail_field', ''));
|
||||
|
||||
if (0 < \strlen($this->sObjectClass) && 0 < \strlen($this->sEmailField))
|
||||
{
|
||||
$sIP = $_SERVER['REMOTE_ADDR'];
|
||||
$sResult = $this->ldapSearch($sEmail);
|
||||
if ( is_array($sResult) ) {
|
||||
$sLogin = $sResult['login'];
|
||||
$sEmail = $sResult['email'];
|
||||
}
|
||||
syslog(LOG_WARNING, "plugins/ldap-login-mapping/index.php:FilterLoginСredentials() auth try: $sIP/$sEmail, resolved as $sLogin/$sEmail");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping(): array
|
||||
{
|
||||
return [
|
||||
Property::NewInstance('domains')
|
||||
->SetLabel('LDAP enabled domains')
|
||||
->SetDefaultValue('example1.com,example2.com'),
|
||||
|
||||
Property::NewInstance('search_domain')
|
||||
->SetLabel('Forced domain')
|
||||
->SetDescription('Force this domain email for LDAP search')
|
||||
->SetDefaultValue('example.com'),
|
||||
|
||||
Property::NewInstance('hostname')
|
||||
->SetLabel('LDAP hostname')
|
||||
->SetDefaultValue('127.0.0.1'),
|
||||
|
||||
Property::NewInstance('port')
|
||||
->SetLabel('LDAP port')
|
||||
->SetType(PluginPropertyType::INT)
|
||||
->SetDefaultValue(389),
|
||||
|
||||
Property::NewInstance('users_dn')
|
||||
->SetLabel('Search base DN')
|
||||
->SetDescription('LDAP users search base DN. No tokens.')
|
||||
->SetDefaultValue('ou=People,dc=domain,dc=com'),
|
||||
|
||||
Property::NewInstance('object_class')
|
||||
->SetLabel('objectClass value')
|
||||
->SetDefaultValue('inetOrgPerson'),
|
||||
|
||||
Property::NewInstance('login_field')
|
||||
->SetLabel('Login field')
|
||||
->SetDefaultValue('uid'),
|
||||
|
||||
Property::NewInstance('mail_field')
|
||||
->SetLabel('Mail field')
|
||||
->SetDefaultValue('mail'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sEmailOrLogin
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function ldapSearch($sEmail)
|
||||
{
|
||||
$bFound = FALSE;
|
||||
foreach ( $this->aDomains as $sDomain ) {
|
||||
$sRegex = '/^[a-z0-9._-]+@' . preg_quote(trim($sDomain)) . '$/i';
|
||||
$this->oLogger->Write('DEBUG regex ' . $sRegex, Type::INFO, 'LDAP');
|
||||
if ( preg_match($sRegex, $sEmail) === 1) {
|
||||
$bFound = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !$bFound ) {
|
||||
$this->oLogger->Write(
|
||||
'preg_match: no match in "' . $sEmail . '" for /^[a-z0-9._-]+@{configured-domains}$/i',
|
||||
Type::INFO,
|
||||
'LDAP');
|
||||
return FALSE;
|
||||
}
|
||||
$sLogin = \MailSo\Base\Utils::GetAccountNameFromEmail($sEmail);
|
||||
|
||||
$this->oLogger->Write('ldap_connect: trying...', Type::INFO, 'LDAP');
|
||||
|
||||
$oCon = @\ldap_connect($this->sHostName, $this->iHostPort);
|
||||
if (!$oCon) return FALSE;
|
||||
|
||||
$this->oLogger->Write('ldap_connect: connected', Type::INFO, 'LDAP');
|
||||
|
||||
@\ldap_set_option($oCon, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||
|
||||
if (!@\ldap_bind($oCon)) {
|
||||
$this->logLdapError($oCon, 'ldap_bind');
|
||||
return FALSE;
|
||||
}
|
||||
$sSearchDn = $this->sUsersDn;
|
||||
$aItems = array($this->sLoginField, $this->sEmailField);
|
||||
if ( 0 < \strlen($this->sSearchDomain) ) {
|
||||
$sFilter = '(&(objectclass='.$this->sObjectClass.')(|('.$this->sEmailField.'='.$sLogin.'@'.$this->sSearchDomain.')('.$this->sLoginField.'='.$sLogin.')))';
|
||||
|
||||
} else {
|
||||
$sFilter = '(&(objectclass='.$this->sObjectClass.')(|('.$this->sEmailField.'='.$sEmail.')('.$this->sLoginField.'='.$sLogin.')))';
|
||||
}
|
||||
$this->oLogger->Write('ldap_search: start: '.$sSearchDn.' / '.$sFilter, Type::INFO, 'LDAP');
|
||||
$oS = @\ldap_search($oCon, $sSearchDn, $sFilter, $aItems, 0, 30, 30);
|
||||
if (!$oS) {
|
||||
$this->logLdapError($oCon, 'ldap_search');
|
||||
return FALSE;
|
||||
}
|
||||
$aEntries = @\ldap_get_entries($oCon, $oS);
|
||||
if (!is_array($aEntries)) {
|
||||
$this->logLdapError($oCon, 'ldap_get_entries');
|
||||
return FALSE;
|
||||
}
|
||||
if (!isset($aEntries[0])) {
|
||||
$this->logLdapError($oCon, 'ldap_get_entries (no result)');
|
||||
return FALSE;
|
||||
}
|
||||
if (!isset($aEntries[0][$this->sLoginField][0])) {
|
||||
$this->logLdapError($oCon, 'ldap_get_entries (no login)');
|
||||
return FALSE;
|
||||
}
|
||||
if (!isset($aEntries[0][$this->sEmailField][0])) {
|
||||
$this->logLdapError($oCon, 'ldap_get_entries (no mail)');
|
||||
return FALSE;
|
||||
}
|
||||
$sLogin = $aEntries[0][$this->sLoginField][0];
|
||||
$sEmail = $aEntries[0][$this->sEmailField][0];
|
||||
$this->oLogger->Write('ldap_search: found "' . $this->sLoginField . ': '.$sLogin . '" and "' . $this->sEmailField . ': '.$sEmail . '"');
|
||||
|
||||
return array(
|
||||
'login' => $sLogin,
|
||||
'email' => $sEmail,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $oCon
|
||||
* @param string $sCmd
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function logLdapError($oCon, $sCmd)
|
||||
{
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$sError = $oCon ? @\ldap_error($oCon) : '';
|
||||
$iErrno = $oCon ? @\ldap_errno($oCon) : 0;
|
||||
|
||||
$this->oLogger->Write($sCmd.' error: '.$sError.' ('.$iErrno.')',
|
||||
Type::WARNING, 'LDAP');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -30,8 +30,10 @@ class OverrideSmtpCredentialsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
|||
$sHost = \trim($this->Config()->Get('plugin', 'smtp_host', ''));
|
||||
$sWhiteList = \trim($this->Config()->Get('plugin', 'override_users', ''));
|
||||
|
||||
if (0 < strlen($sWhiteList) && 0 < \strlen($sHost) && \RainLoop\Plugins\Helper::ValidateWildcardValues($sEmail, $sWhiteList))
|
||||
$sFoundValue = '';
|
||||
if (0 < strlen($sWhiteList) && 0 < \strlen($sHost) && \RainLoop\Plugins\Helper::ValidateWildcardValues($sEmail, $sWhiteList, $sFoundValue))
|
||||
{
|
||||
\SnappyMail\LOG::debug('SMTP Override', "{$sEmail} matched {$sFoundValue}");
|
||||
$aSmtpCredentials['Host'] = $sHost;
|
||||
$aSmtpCredentials['Port'] = (int) $this->Config()->Get('plugin', 'smtp_port', 25);
|
||||
|
||||
|
|
@ -53,6 +55,10 @@ class OverrideSmtpCredentialsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
|||
$aSmtpCredentials['Login'] = \trim($this->Config()->Get('plugin', 'smtp_user', ''));
|
||||
$aSmtpCredentials['Password'] = (string) $this->Config()->Get('plugin', 'smtp_password', '');
|
||||
}
|
||||
else
|
||||
{
|
||||
\SnappyMail\LOG::debug('SMTP Override', "{$sEmail} no match");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ class SnowfallOnLoginScreenPlugin extends \RainLoop\Plugins\AbstractPlugin
|
|||
{
|
||||
const
|
||||
NAME = 'Snowfall on login screen',
|
||||
VERSION = '2.0',
|
||||
VERSION = '2.1',
|
||||
CATEGORY = 'Fun',
|
||||
DESCRIPTION = 'Snowfall on login screen (just for fun).';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,17 @@
|
|||
|
||||
if (!/iphone|ipod|ipad|android/i.test(navigator.userAgent))
|
||||
{
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
if (window.snowFall && window.rl && !rl.settings.get('Auth'))
|
||||
{
|
||||
window.snowFall.snow(document.getElementsByTagName('body'), {
|
||||
shadow: true, round: true, minSize: 2, maxSize: 5
|
||||
});
|
||||
}
|
||||
});
|
||||
if (window.snowFall && window.rl)
|
||||
{
|
||||
let body = document.body;
|
||||
addEventListener('sm-show-screen', e => {
|
||||
if ('login' == e.detail) {
|
||||
window.snowFall.snow(body, {
|
||||
shadow: true, round: true, minSize: 2, maxSize: 5
|
||||
});
|
||||
} else if (body.snow) {
|
||||
body.snow.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
*/
|
||||
|
||||
// Paul Irish requestAnimationFrame polyfill
|
||||
(function(window) {
|
||||
(window => {
|
||||
var lastTime = 0;
|
||||
var vendors = ['webkit', 'moz'];
|
||||
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
|
||||
|
|
@ -57,11 +57,10 @@
|
|||
}
|
||||
|
||||
if (!window.requestAnimationFrame)
|
||||
window.requestAnimationFrame = function(callback, element) {
|
||||
window.requestAnimationFrame = callback => {
|
||||
var currTime = new Date().getTime();
|
||||
var timeToCall = window.Math.max(0, 16 - (currTime - lastTime));
|
||||
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
|
||||
timeToCall);
|
||||
var id = window.setTimeout(() => callback(currTime + timeToCall), timeToCall);
|
||||
lastTime = currTime + timeToCall;
|
||||
return id;
|
||||
};
|
||||
|
|
@ -70,7 +69,7 @@
|
|||
window.cancelAnimationFrame = function(id) {
|
||||
clearTimeout(id);
|
||||
};
|
||||
}(window));
|
||||
})(window);
|
||||
|
||||
var snowFall = (function(){
|
||||
function jSnow(){
|
||||
|
|
@ -248,28 +247,14 @@ var snowFall = (function(){
|
|||
cancelAnimationFrame(snowTimeout);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
return{
|
||||
snow : function(elements, options){
|
||||
snow : (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();
|
||||
}
|
||||
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);
|
||||
}
|
||||
new jSnow().snow(elements, options);
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ LABEL_TWO_FACTOR_STATUS = "Status"
|
|||
LABEL_TWO_FACTOR_SECRET = "Geheime sleutel"
|
||||
LABEL_TWO_FACTOR_BACKUP_CODES = "Backup codes"
|
||||
BUTTON_CREATE = "Nieuwe geheime sleutel aanmaken"
|
||||
BUTTON_ACTIVATE = "Activate"
|
||||
BUTTON_ACTIVATE = "Activeren"
|
||||
LINK_TEST = "test"
|
||||
BUTTON_SHOW_SECRET = "Bekijk geheime sleutel"
|
||||
BUTTON_HIDE_SECRET = "Verberg geheime sleutel"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue