[Web] Feature: Add password policy
parent
616226be8a
commit
5ea649b292
|
@ -23,6 +23,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||||
<li role="presentation"><a href="#tab-config-quarantine" aria-controls="tab-config-quarantine" role="tab" data-toggle="tab"><?=$lang['admin']['quarantine'];?></a></li>
|
<li role="presentation"><a href="#tab-config-quarantine" aria-controls="tab-config-quarantine" role="tab" data-toggle="tab"><?=$lang['admin']['quarantine'];?></a></li>
|
||||||
<li role="presentation"><a href="#tab-config-quota" aria-controls="tab-config-quota" role="tab" data-toggle="tab"><?=$lang['admin']['quota_notifications'];?></a></li>
|
<li role="presentation"><a href="#tab-config-quota" aria-controls="tab-config-quota" role="tab" data-toggle="tab"><?=$lang['admin']['quota_notifications'];?></a></li>
|
||||||
<li role="presentation"><a href="#tab-config-rsettings" aria-controls="tab-config-rsettings" role="tab" data-toggle="tab"><?=$lang['admin']['rspamd_settings_map'];?></a></li>
|
<li role="presentation"><a href="#tab-config-rsettings" aria-controls="tab-config-rsettings" role="tab" data-toggle="tab"><?=$lang['admin']['rspamd_settings_map'];?></a></li>
|
||||||
|
<li role="presentation"><a href="#tab-config-password-policy" aria-controls="tab-config-password-policy" role="tab" data-toggle="tab"><?=$lang['admin']['password_policy'];?></a></li>
|
||||||
<li role="presentation"><a href="#tab-config-customize" aria-controls="tab-config-customize" role="tab" data-toggle="tab"><?=$lang['admin']['customize'];?></a></li>
|
<li role="presentation"><a href="#tab-config-customize" aria-controls="tab-config-customize" role="tab" data-toggle="tab"><?=$lang['admin']['customize'];?></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
@ -77,7 +78,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||||
foreach ($tfa_data['additional'] as $key_info) {
|
foreach ($tfa_data['additional'] as $key_info) {
|
||||||
?>
|
?>
|
||||||
<form style="display:inline;" method="post">
|
<form style="display:inline;" method="post">
|
||||||
<input type="hidden" name="unset_tfa_key" value="<?=$key_info['id'];?>" />
|
<input type="hidden" name="unset_tfa_key" value="<?=$key_info['id'];?>">
|
||||||
<div style="padding:4px;margin:4px" class="label label-keys label-<?=($_SESSION['tfa_id'] == $key_info['id']) ? 'success' : 'default'; ?>">
|
<div style="padding:4px;margin:4px" class="label label-keys label-<?=($_SESSION['tfa_id'] == $key_info['id']) ? 'success' : 'default'; ?>">
|
||||||
<?=$key_info['key_id'];?>
|
<?=$key_info['key_id'];?>
|
||||||
<a href="#" style="font-weight:bold;color:white" onClick="$(this).closest('form').submit()">[<?=$lang['admin']['remove'];?>]</a>
|
<a href="#" style="font-weight:bold;color:white" onClick="$(this).closest('form').submit()">[<?=$lang['admin']['remove'];?>]</a>
|
||||||
|
@ -128,7 +129,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||||
</td>
|
</td>
|
||||||
<td style="min-width:240px;text-align: right">
|
<td style="min-width:240px;text-align: right">
|
||||||
<form style="display:inline;" method="post">
|
<form style="display:inline;" method="post">
|
||||||
<input type="hidden" name="unset_fido2_key" value="<?=$key_info['cid'];?>" />
|
<input type="hidden" name="unset_fido2_key" value="<?=$key_info['cid'];?>">
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<a href="#" class="btn btn-xs btn-default" data-cid="<?=$key_info['cid'];?>" data-subject="<?=base64_encode($key_info['subject']);?>" data-toggle="modal" data-target="#fido2ChangeFn"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['fido2']['rename'];?></a>
|
<a href="#" class="btn btn-xs btn-default" data-cid="<?=$key_info['cid'];?>" data-subject="<?=base64_encode($key_info['subject']);?>" data-toggle="modal" data-target="#fido2ChangeFn"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['fido2']['rename'];?></a>
|
||||||
<a href="#" onClick='return confirm("<?=$lang['admin']['ays'];?>")?$(this).closest("form").submit():"";' class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['admin']['remove'];?></a>
|
<a href="#" onClick='return confirm("<?=$lang['admin']['ays'];?>")?$(this).closest("form").submit():"";' class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['admin']['remove'];?></a>
|
||||||
|
@ -381,7 +382,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
<img class="img-responsive" src="/img/rspamd_logo.png" alt="Rspamd UI" />
|
<img class="img-responsive" src="/img/rspamd_logo.png" alt="Rspamd UI">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -507,7 +508,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||||
($GLOBALS['SHOW_DKIM_PRIV_KEYS'] === true) ?: $dkim['privkey'] = base64_encode('Please set $SHOW_DKIM_PRIV_KEYS to true to show DKIM private keys.');
|
($GLOBALS['SHOW_DKIM_PRIV_KEYS'] === true) ?: $dkim['privkey'] = base64_encode('Please set $SHOW_DKIM_PRIV_KEYS to true to show DKIM private keys.');
|
||||||
?>
|
?>
|
||||||
<div class="row collapse in dkim_key_valid">
|
<div class="row collapse in dkim_key_valid">
|
||||||
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>" /></div>
|
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>"></div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<p><?=$lang['admin']['domain'];?>: <strong><?=htmlspecialchars($domain);?></strong>
|
<p><?=$lang['admin']['domain'];?>: <strong><?=htmlspecialchars($domain);?></strong>
|
||||||
<p class="dkim-label"><span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span></p>
|
<p class="dkim-label"><span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span></p>
|
||||||
|
@ -526,7 +527,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||||
else {
|
else {
|
||||||
?>
|
?>
|
||||||
<div class="row collapse in dkim_key_missing">
|
<div class="row collapse in dkim_key_missing">
|
||||||
<div class="col-md-1"><input class="dkim_missing" type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>" disabled /></div>
|
<div class="col-md-1"><input class="dkim_missing" type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>" disabled></div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<p><?=$lang['admin']['domain'];?>: <strong><?=htmlspecialchars($domain);?></strong><br><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p>
|
<p><?=$lang['admin']['domain'];?>: <strong><?=htmlspecialchars($domain);?></strong><br><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -541,7 +542,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||||
($GLOBALS['SHOW_DKIM_PRIV_KEYS'] === true) ?: $dkim['privkey'] = base64_encode('Please set $SHOW_DKIM_PRIV_KEYS to true to show DKIM private keys.');
|
($GLOBALS['SHOW_DKIM_PRIV_KEYS'] === true) ?: $dkim['privkey'] = base64_encode('Please set $SHOW_DKIM_PRIV_KEYS to true to show DKIM private keys.');
|
||||||
?>
|
?>
|
||||||
<div class="row collapse in dkim_key_valid">
|
<div class="row collapse in dkim_key_valid">
|
||||||
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$alias_domain;?>" /></div>
|
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$alias_domain;?>"></div>
|
||||||
<div class="col-md-2 col-md-offset-1">
|
<div class="col-md-2 col-md-offset-1">
|
||||||
<p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong></small>
|
<p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong></small>
|
||||||
<p class="dkim-label"><span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span></p>
|
<p class="dkim-label"><span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span></p>
|
||||||
|
@ -560,7 +561,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||||
else {
|
else {
|
||||||
?>
|
?>
|
||||||
<div class="row collapse in dkim_key_missing">
|
<div class="row collapse in dkim_key_missing">
|
||||||
<div class="col-md-1"><input class="dkim_missing" type="checkbox" data-id="dkim" name="multi_select" value="<?=$alias_domain;?>" disabled /></div>
|
<div class="col-md-1"><input class="dkim_missing" type="checkbox" data-id="dkim" name="multi_select" value="<?=$alias_domain;?>" disabled></div>
|
||||||
<div class="col-md-2 col-md-offset-1">
|
<div class="col-md-2 col-md-offset-1">
|
||||||
<p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong><br></small><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p>
|
<p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong><br></small><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -577,7 +578,7 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||||
($GLOBALS['SHOW_DKIM_PRIV_KEYS'] === true) ?: $dkim['privkey'] = base64_encode('Please set $SHOW_DKIM_PRIV_KEYS to true to show DKIM private keys.');
|
($GLOBALS['SHOW_DKIM_PRIV_KEYS'] === true) ?: $dkim['privkey'] = base64_encode('Please set $SHOW_DKIM_PRIV_KEYS to true to show DKIM private keys.');
|
||||||
?>
|
?>
|
||||||
<div class="row collapse in dkim_key_unused">
|
<div class="row collapse in dkim_key_unused">
|
||||||
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$blind;?>" /></div>
|
<div class="col-md-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$blind;?>"></div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<p><?=$lang['admin']['domain'];?>: <strong><?=htmlspecialchars($blind);?></strong>
|
<p><?=$lang['admin']['domain'];?>: <strong><?=htmlspecialchars($blind);?></strong>
|
||||||
<p class="dkim-label"><span class="label label-warning"><?=$lang['admin']['dkim_key_unused'];?></span></p>
|
<p class="dkim-label"><span class="label label-warning"><?=$lang['admin']['dkim_key_unused'];?></span></p>
|
||||||
|
@ -1212,6 +1213,49 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div role="tabpanel" class="tab-pane" id="tab-config-password-policy">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading"><?=$lang['admin']['password_policy'];?></div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<?php $password_complexity = password_complexity('get'); ?>
|
||||||
|
<form class="form-horizontal" data-id="passwordpolicy" role="form" method="post">
|
||||||
|
<?php
|
||||||
|
foreach ($password_complexity as $name => $value) {
|
||||||
|
if ($name == 'length') {
|
||||||
|
?>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-3" for="<?=$name;?>"><?=$lang['admin']['password_length'];?>:</label>
|
||||||
|
<div class="col-sm-2">
|
||||||
|
<input type="number" class="form-control" min="3" max="64" name="<?=$name;?>" id="<?=$name;?>" value="<?=$value;?>" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
} else {
|
||||||
|
?>
|
||||||
|
<input type="hidden" name="<?=$name;?>" value="0">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-3 col-sm-9">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="<?=$name;?>" id="<?=$name;?>" value="1" <?=($value == 1) ? 'checked' : null;?>> <?=$lang['admin']["password_policy_$name"];?>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-3 col-sm-9">
|
||||||
|
<div class="btn-group">
|
||||||
|
<button class="btn btn-sm btn-success" data-item="passwordpolicy" data-action="edit_selected" data-id="passwordpolicy" data-api-url='edit/passwordpolicy' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div role="tabpanel" class="tab-pane" id="tab-sys-mails">
|
<div role="tabpanel" class="tab-pane" id="tab-sys-mails">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading"><?=$lang['admin']['sys_mails'];?></div>
|
<div class="panel-heading"><?=$lang['admin']['sys_mails'];?></div>
|
||||||
|
|
|
@ -48,40 +48,23 @@ function admin($_action, $_data = null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!empty($password) && !empty($password2)) {
|
if (password_check($password_new, $password_new2) !== true) {
|
||||||
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
|
||||||
'msg' => 'password_complexity'
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ($password != $password2) {
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
|
||||||
'msg' => 'password_mismatch'
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$password_hashed = hash_password($password);
|
|
||||||
$stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`)
|
|
||||||
VALUES (:username, :password_hashed, '1', :active)");
|
|
||||||
$stmt->execute(array(
|
|
||||||
':username' => $username,
|
|
||||||
':password_hashed' => $password_hashed,
|
|
||||||
':active' => $active
|
|
||||||
));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
|
||||||
'msg' => 'password_empty'
|
|
||||||
);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// support pre hashed passwords
|
||||||
|
if (preg_match('/^{(ARGON2I|ARGON2ID|BLF-CRYPT|CLEAR|CLEARTEXT|CRYPT|DES-CRYPT|LDAP-MD5|MD5|MD5-CRYPT|PBKDF2|PLAIN|PLAIN-MD4|PLAIN-MD5|PLAIN-TRUNC|PLAIN-TRUNC|SHA|SHA1|SHA256|SHA256-CRYPT|SHA512|SHA512-CRYPT|SMD5|SSHA|SSHA256|SSHA512)}/i', $password)) {
|
||||||
|
$password_hashed = $password_new;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$password_hashed = hash_password($password_new);
|
||||||
|
}
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`)
|
||||||
|
VALUES (:username, :password_hashed, '1', :active)");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':username' => $username,
|
||||||
|
':password_hashed' => $password_hashed,
|
||||||
|
':active' => $active
|
||||||
|
));
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
@ -145,23 +128,16 @@ function admin($_action, $_data = null) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!empty($password) && !empty($password2)) {
|
if (!empty($password) && !empty($password2)) {
|
||||||
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
|
if (password_check($password, $password2) !== true) {
|
||||||
$_SESSION['return'][] = array(
|
return false;
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
|
||||||
'msg' => 'password_complexity'
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if ($password != $password2) {
|
// support pre hashed passwords
|
||||||
$_SESSION['return'][] = array(
|
if (preg_match('/^{(ARGON2I|ARGON2ID|BLF-CRYPT|CLEAR|CLEARTEXT|CRYPT|DES-CRYPT|LDAP-MD5|MD5|MD5-CRYPT|PBKDF2|PLAIN|PLAIN-MD4|PLAIN-MD5|PLAIN-TRUNC|PLAIN-TRUNC|SHA|SHA1|SHA256|SHA256-CRYPT|SHA512|SHA512-CRYPT|SMD5|SSHA|SSHA256|SSHA512)}/i', $password)) {
|
||||||
'type' => 'danger',
|
$password_hashed = $password;
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
}
|
||||||
'msg' => 'password_mismatch'
|
else {
|
||||||
);
|
$password_hashed = hash_password($password);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
$password_hashed = hash_password($password);
|
|
||||||
$stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active, `password` = :password_hashed WHERE `username` = :username");
|
$stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active, `password` = :password_hashed WHERE `username` = :username");
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':password_hashed' => $password_hashed,
|
':password_hashed' => $password_hashed,
|
||||||
|
|
|
@ -21,7 +21,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
if (!is_valid_domain_name($domain) || !is_numeric($key_length)) {
|
if (!is_valid_domain_name($domain) || !is_numeric($key_length)) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
|
@ -29,7 +29,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
if ($redis->hGet('DKIM_PUB_KEYS', $domain)) {
|
if ($redis->hGet('DKIM_PUB_KEYS', $domain)) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
|
@ -37,7 +37,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
if (!ctype_alnum(str_replace(['-', '_'], '', $dkim_selector))) {
|
if (!ctype_alnum(str_replace(['-', '_'], '', $dkim_selector))) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
|
@ -62,7 +62,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('redis_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
|
@ -76,7 +76,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('redis_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
|
@ -84,14 +84,14 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
}
|
}
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('dkim_added', $domain)
|
'msg' => array('dkim_added', $domain)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
|
@ -102,7 +102,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => 'access_denied'
|
'msg' => 'access_denied'
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
|
@ -112,7 +112,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
if (empty($from_domain_dkim)) {
|
if (empty($from_domain_dkim)) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('dkim_domain_or_sel_invalid', $from_domain)
|
'msg' => array('dkim_domain_or_sel_invalid', $from_domain)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
|
@ -128,14 +128,14 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('redis_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('dkim_duplicated', $from_domain, $to_domain)
|
'msg' => array('dkim_duplicated', $from_domain, $to_domain)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => 'access_denied'
|
'msg' => 'access_denied'
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
|
@ -156,7 +156,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
if ($ssl_error = openssl_error_string()) {
|
if ($ssl_error = openssl_error_string()) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('private_key_error', $ssl_error)
|
'msg' => array('private_key_error', $ssl_error)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
|
@ -173,7 +173,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
if (!is_valid_domain_name($domain)) {
|
if (!is_valid_domain_name($domain)) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
|
@ -182,7 +182,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
if ($overwrite_existing == 0) {
|
if ($overwrite_existing == 0) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('dkim_domain_or_sel_exists', $domain)
|
'msg' => array('dkim_domain_or_sel_exists', $domain)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
|
@ -191,7 +191,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
if (!ctype_alnum($dkim_selector)) {
|
if (!ctype_alnum($dkim_selector)) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
|
@ -205,7 +205,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('redis_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
|
@ -218,14 +218,14 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('redis_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('dkim_added', $domain)
|
'msg' => array('dkim_added', $domain)
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
|
@ -270,7 +270,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => 'access_denied'
|
'msg' => 'access_denied'
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
|
@ -286,7 +286,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => 'access_denied'
|
'msg' => 'access_denied'
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
|
@ -295,7 +295,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
if (!is_valid_domain_name($domain)) {
|
if (!is_valid_domain_name($domain)) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
'msg' => array('dkim_domain_or_sel_invalid', $domain)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
|
@ -309,14 +309,14 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('redis_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data, $privkey),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('dkim_removed', htmlspecialchars($domain))
|
'msg' => array('dkim_removed', htmlspecialchars($domain))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,61 +65,44 @@ function domain_admin($_action, $_data = null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!empty($password) && !empty($password2)) {
|
if (password_check($password, $password2) !== true) {
|
||||||
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
|
continue;
|
||||||
$_SESSION['return'][] = array(
|
}
|
||||||
'type' => 'danger',
|
// support pre hashed passwords
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
if (preg_match('/^{(ARGON2I|ARGON2ID|BLF-CRYPT|CLEAR|CLEARTEXT|CRYPT|DES-CRYPT|LDAP-MD5|MD5|MD5-CRYPT|PBKDF2|PLAIN|PLAIN-MD4|PLAIN-MD5|PLAIN-TRUNC|PLAIN-TRUNC|SHA|SHA1|SHA256|SHA256-CRYPT|SHA512|SHA512-CRYPT|SMD5|SSHA|SSHA256|SSHA512)}/i', $password)) {
|
||||||
'msg' => 'password_complexity'
|
$password_hashed = $password;
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ($password != $password2) {
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
|
||||||
'msg' => 'password_mismatch'
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$password_hashed = hash_password($password);
|
|
||||||
$valid_domains = 0;
|
|
||||||
foreach ($domains as $domain) {
|
|
||||||
if (!is_valid_domain_name($domain) || mailbox('get', 'domain_details', $domain) === false) {
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
|
||||||
'msg' => array('domain_invalid', htmlspecialchars($domain))
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$valid_domains++;
|
|
||||||
$stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`)
|
|
||||||
VALUES (:username, :domain, :created, :active)");
|
|
||||||
$stmt->execute(array(
|
|
||||||
':username' => $username,
|
|
||||||
':domain' => $domain,
|
|
||||||
':created' => date('Y-m-d H:i:s'),
|
|
||||||
':active' => $active
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if ($valid_domains != 0) {
|
|
||||||
$stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`)
|
|
||||||
VALUES (:username, :password_hashed, '0', :active)");
|
|
||||||
$stmt->execute(array(
|
|
||||||
':username' => $username,
|
|
||||||
':password_hashed' => $password_hashed,
|
|
||||||
':active' => $active
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$_SESSION['return'][] = array(
|
$password_hashed = hash_password($password);
|
||||||
'type' => 'danger',
|
}
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
$valid_domains = 0;
|
||||||
'msg' => 'password_empty'
|
foreach ($domains as $domain) {
|
||||||
);
|
if (!is_valid_domain_name($domain) || mailbox('get', 'domain_details', $domain) === false) {
|
||||||
return false;
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
'msg' => array('domain_invalid', htmlspecialchars($domain))
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$valid_domains++;
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`)
|
||||||
|
VALUES (:username, :domain, :created, :active)");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':username' => $username,
|
||||||
|
':domain' => $domain,
|
||||||
|
':created' => date('Y-m-d H:i:s'),
|
||||||
|
':active' => $active
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if ($valid_domains != 0) {
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`)
|
||||||
|
VALUES (:username, :password_hashed, '0', :active)");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':username' => $username,
|
||||||
|
':password_hashed' => $password_hashed,
|
||||||
|
':active' => $active
|
||||||
|
));
|
||||||
}
|
}
|
||||||
$stmt = $pdo->prepare("INSERT INTO `da_acl` (`username`) VALUES (:username)");
|
$stmt = $pdo->prepare("INSERT INTO `da_acl` (`username`) VALUES (:username)");
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
|
@ -219,23 +202,16 @@ function domain_admin($_action, $_data = null) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!empty($password) && !empty($password2)) {
|
if (!empty($password) && !empty($password2)) {
|
||||||
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
|
if (password_check($password, $password2) !== true) {
|
||||||
$_SESSION['return'][] = array(
|
return false;
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
|
||||||
'msg' => 'password_complexity'
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if ($password != $password2) {
|
// support pre hashed passwords
|
||||||
$_SESSION['return'][] = array(
|
if (preg_match('/^{(ARGON2I|ARGON2ID|BLF-CRYPT|CLEAR|CLEARTEXT|CRYPT|DES-CRYPT|LDAP-MD5|MD5|MD5-CRYPT|PBKDF2|PLAIN|PLAIN-MD4|PLAIN-MD5|PLAIN-TRUNC|PLAIN-TRUNC|SHA|SHA1|SHA256|SHA256-CRYPT|SHA512|SHA512-CRYPT|SMD5|SSHA|SSHA256|SSHA512)}/i', $password)) {
|
||||||
'type' => 'danger',
|
$password_hashed = $password;
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
}
|
||||||
'msg' => 'password_mismatch'
|
else {
|
||||||
);
|
$password_hashed = hash_password($password);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
$password_hashed = hash_password($password);
|
|
||||||
$stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active, `password` = :password_hashed WHERE `username` = :username");
|
$stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active, `password` = :password_hashed WHERE `username` = :username");
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':password_hashed' => $password_hashed,
|
':password_hashed' => $password_hashed,
|
||||||
|
@ -296,30 +272,15 @@ function domain_admin($_action, $_data = null) {
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!empty($password_new2) && !empty($password_new)) {
|
if (password_check($password_new, $password_new2) !== true) {
|
||||||
if ($password_new2 != $password_new) {
|
return false;
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
|
||||||
'msg' => 'password_mismatch'
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password_new)) {
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
|
||||||
'msg' => 'password_complexity'
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$password_hashed = hash_password($password_new);
|
|
||||||
$stmt = $pdo->prepare("UPDATE `admin` SET `password` = :password_hashed WHERE `username` = :username");
|
|
||||||
$stmt->execute(array(
|
|
||||||
':password_hashed' => $password_hashed,
|
|
||||||
':username' => $username
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
$password_hashed = hash_password($password_new);
|
||||||
|
$stmt = $pdo->prepare("UPDATE `admin` SET `password` = :password_hashed WHERE `username` = :username");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':password_hashed' => $password_hashed,
|
||||||
|
':username' => $username
|
||||||
|
));
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
|
|
@ -114,6 +114,132 @@ function hash_password($password) {
|
||||||
}
|
}
|
||||||
return $pw_hash;
|
return $pw_hash;
|
||||||
}
|
}
|
||||||
|
function password_complexity($_action, $_data = null) {
|
||||||
|
global $redis;
|
||||||
|
global $lang;
|
||||||
|
switch ($_action) {
|
||||||
|
case 'edit':
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
|
'msg' => 'access_denied'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$is_now = password_complexity('get');
|
||||||
|
if (!empty($is_now)) {
|
||||||
|
$length = (isset($_data['length']) && intval($_data['length']) >= 3) ? intval($_data['length']) : $is_now['length'];
|
||||||
|
$chars = (isset($_data['chars'])) ? intval($_data['chars']) : $is_now['chars'];
|
||||||
|
$lowerupper = (isset($_data['lowerupper'])) ? intval($_data['lowerupper']) : $is_now['lowerupper'];
|
||||||
|
$special_chars = (isset($_data['special_chars'])) ? intval($_data['special_chars']) : $is_now['special_chars'];
|
||||||
|
$numbers = (isset($_data['numbers'])) ? intval($_data['numbers']) : $is_now['numbers'];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$redis->hMSet('PASSWD_POLICY', [
|
||||||
|
'length' => $length,
|
||||||
|
'chars' => $chars,
|
||||||
|
'special_chars' => $special_chars,
|
||||||
|
'lowerupper' => $lowerupper,
|
||||||
|
'numbers' => $numbers
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
catch (RedisException $e) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
|
'msg' => array('redis_error', $e)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
|
'msg' => print_r($_data, true)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'get':
|
||||||
|
try {
|
||||||
|
$length = $redis->hGet('PASSWD_POLICY', 'length');
|
||||||
|
$chars = $redis->hGet('PASSWD_POLICY', 'chars');
|
||||||
|
$special_chars = $redis->hGet('PASSWD_POLICY', 'special_chars');
|
||||||
|
$lowerupper = $redis->hGet('PASSWD_POLICY', 'lowerupper');
|
||||||
|
$numbers = $redis->hGet('PASSWD_POLICY', 'numbers');
|
||||||
|
return array(
|
||||||
|
'length' => $length,
|
||||||
|
'chars' => $chars,
|
||||||
|
'special_chars' => $special_chars,
|
||||||
|
'lowerupper' => $lowerupper,
|
||||||
|
'numbers' => $numbers
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (RedisException $e) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
|
'msg' => array('redis_error', $e)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 'html':
|
||||||
|
$policies = password_complexity('get');
|
||||||
|
foreach ($policies as $name => $value) {
|
||||||
|
if ($value != 0) {
|
||||||
|
$policy_text[] = sprintf($lang['admin']["password_policy_$name"], $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '<p class="help-block small">- ' . implode('<br>- ', $policy_text) . '</p>';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function password_check($password1, $password2) {
|
||||||
|
$password_complexity = password_complexity('get');
|
||||||
|
|
||||||
|
if (empty($password1) || empty($password2)) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type),
|
||||||
|
'msg' => 'password_complexity'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($password1 != $password2) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type),
|
||||||
|
'msg' => 'password_mismatch'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$given_password['length'] = strlen($password1);
|
||||||
|
$given_password['special_chars'] = preg_match('/[^a-zA-Z\d]/', $password1);
|
||||||
|
$given_password['chars'] = preg_match('/[a-zA-Z]/',$password1);
|
||||||
|
$given_password['numbers'] = preg_match('/\d/', $password1);
|
||||||
|
$lower = strlen(preg_replace("/[^a-z]/", '', $password1));
|
||||||
|
$upper = strlen(preg_replace("/[^A-Z]/", '', $password1));
|
||||||
|
$given_password['lowerupper'] = ($lower > 0 && $upper > 0) ? true : false;
|
||||||
|
|
||||||
|
if (
|
||||||
|
($given_password['length'] < $password_complexity['length']) ||
|
||||||
|
($password_complexity['special_chars'] == 1 && (intval($given_password['special_chars']) != $password_complexity['special_chars'])) ||
|
||||||
|
($password_complexity['chars'] == 1 && (intval($given_password['chars']) != $password_complexity['chars'])) ||
|
||||||
|
($password_complexity['numbers'] == 1 && (intval($given_password['numbers']) != $password_complexity['numbers'])) ||
|
||||||
|
($password_complexity['lowerupper'] == 1 && (intval($given_password['lowerupper']) != $password_complexity['lowerupper']))
|
||||||
|
) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type),
|
||||||
|
'msg' => 'password_complexity'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
function last_login($user) {
|
function last_login($user) {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
$stmt = $pdo->prepare('SELECT `remote`, `time` FROM `logs`
|
$stmt = $pdo->prepare('SELECT `remote`, `time` FROM `logs`
|
||||||
|
|
|
@ -1045,32 +1045,15 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!empty($password) && !empty($password2)) {
|
if (password_check($password, $password2) !== true) {
|
||||||
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
|
return false;
|
||||||
$_SESSION['return'][] = array(
|
}
|
||||||
'type' => 'danger',
|
// support pre hashed passwords
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
if (preg_match('/^{(ARGON2I|ARGON2ID|BLF-CRYPT|CLEAR|CLEARTEXT|CRYPT|DES-CRYPT|LDAP-MD5|MD5|MD5-CRYPT|PBKDF2|PLAIN|PLAIN-MD4|PLAIN-MD5|PLAIN-TRUNC|PLAIN-TRUNC|SHA|SHA1|SHA256|SHA256-CRYPT|SHA512|SHA512-CRYPT|SMD5|SSHA|SSHA256|SSHA512)}/i', $password)) {
|
||||||
'msg' => 'password_complexity'
|
$password_hashed = $password;
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ($password != $password2) {
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
|
||||||
'msg' => 'password_mismatch'
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$password_hashed = hash_password($password);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$_SESSION['return'][] = array(
|
$password_hashed = hash_password($password);
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
|
||||||
'msg' => 'password_empty'
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if ($MailboxData['count'] >= $DomainData['mailboxes']) {
|
if ($MailboxData['count'] >= $DomainData['mailboxes']) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
|
@ -2599,38 +2582,23 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!empty($password) && !empty($password2)) {
|
if (password_check($password, $password2) !== true) {
|
||||||
if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
|
continue;
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
|
||||||
'msg' => 'password_complexity'
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ($password != $password2) {
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
|
||||||
'msg' => 'password_mismatch'
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// support pre hashed passwords
|
|
||||||
if (preg_match('/^{(ARGON2I|ARGON2ID|BLF-CRYPT|CLEAR|CLEARTEXT|CRYPT|DES-CRYPT|LDAP-MD5|MD5|MD5-CRYPT|PBKDF2|PLAIN|PLAIN-MD4|PLAIN-MD5|PLAIN-TRUNC|PLAIN-TRUNC|SHA|SHA1|SHA256|SHA256-CRYPT|SHA512|SHA512-CRYPT|SMD5|SSHA|SSHA256|SSHA512)}/i', $password)) {
|
|
||||||
$password_hashed = $password;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$password_hashed = hash_password($password);
|
|
||||||
}
|
|
||||||
$stmt = $pdo->prepare("UPDATE `mailbox` SET
|
|
||||||
`password` = :password_hashed
|
|
||||||
WHERE `username` = :username");
|
|
||||||
$stmt->execute(array(
|
|
||||||
':password_hashed' => $password_hashed,
|
|
||||||
':username' => $username
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
// support pre hashed passwords
|
||||||
|
if (preg_match('/^{(ARGON2I|ARGON2ID|BLF-CRYPT|CLEAR|CLEARTEXT|CRYPT|DES-CRYPT|LDAP-MD5|MD5|MD5-CRYPT|PBKDF2|PLAIN|PLAIN-MD4|PLAIN-MD5|PLAIN-TRUNC|PLAIN-TRUNC|SHA|SHA1|SHA256|SHA256-CRYPT|SHA512|SHA512-CRYPT|SMD5|SSHA|SSHA256|SSHA512)}/i', $password)) {
|
||||||
|
$password_hashed = $password;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$password_hashed = hash_password($password);
|
||||||
|
}
|
||||||
|
$stmt = $pdo->prepare("UPDATE `mailbox` SET
|
||||||
|
`password` = :password_hashed
|
||||||
|
WHERE `username` = :username");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':password_hashed' => $password_hashed,
|
||||||
|
':username' => $username
|
||||||
|
));
|
||||||
// We could either set alias = 1 if alias = 2 or tune the Postfix alias table (that's what we did, TODO: to it the other way)
|
// We could either set alias = 1 if alias = 2 or tune the Postfix alias table (that's what we did, TODO: to it the other way)
|
||||||
$stmt = $pdo->prepare("UPDATE `alias` SET
|
$stmt = $pdo->prepare("UPDATE `alias` SET
|
||||||
`active` = :active
|
`active` = :active
|
||||||
|
|
|
@ -90,14 +90,6 @@ $AVAILABLE_LANGUAGES = array('ca', 'cs', 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu
|
||||||
// WARNING: Only lumen is loaded locally. Enabling any other theme, will download external sources.
|
// WARNING: Only lumen is loaded locally. Enabling any other theme, will download external sources.
|
||||||
$DEFAULT_THEME = 'lumen';
|
$DEFAULT_THEME = 'lumen';
|
||||||
|
|
||||||
// Password complexity as regular expression
|
|
||||||
// Min. 6 characters
|
|
||||||
$PASSWD_REGEP = '.{6,}';
|
|
||||||
// Min. 6 characters, which must include at least one uppercase letter, one lowercase letter and one number
|
|
||||||
// $PASSWD_REGEP = '^(?=.*[A-Z])(?=.*[0-9])(?=.*[a-z]).{6,}$';
|
|
||||||
// Min. 6 characters, which must include at least one letter and one number
|
|
||||||
// $PASSWD_REGEP = '^(?=.*[0-9])(?=.*[A-Za-z]).{6,}$';
|
|
||||||
|
|
||||||
// Show DKIM private keys - false by default
|
// Show DKIM private keys - false by default
|
||||||
$SHOW_DKIM_PRIV_KEYS = false;
|
$SHOW_DKIM_PRIV_KEYS = false;
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,14 @@ $(document).ready(function() {
|
||||||
// selectpicker
|
// selectpicker
|
||||||
$('select').selectpicker();
|
$('select').selectpicker();
|
||||||
|
|
||||||
// haveibeenpwned?
|
// haveibeenpwned and passwd policy
|
||||||
|
$.ajax({
|
||||||
|
url: '/api/v1/get/passwordpolicy/html',
|
||||||
|
type: 'GET',
|
||||||
|
success: function(res) {
|
||||||
|
$(".hibp-out").after(res);
|
||||||
|
}
|
||||||
|
});
|
||||||
$('[data-hibp]').after('<p class="small haveibeenpwned">↪ Check against haveibeenpwned.com</p><span class="hibp-out"></span>');
|
$('[data-hibp]').after('<p class="small haveibeenpwned">↪ Check against haveibeenpwned.com</p><span class="hibp-out"></span>');
|
||||||
$('[data-hibp]').on('input', function() {
|
$('[data-hibp]').on('input', function() {
|
||||||
out_field = $(this).next('.haveibeenpwned').next('.hibp-out').text('').attr('class', 'hibp-out');
|
out_field = $(this).next('.haveibeenpwned').next('.hibp-out').text('').attr('class', 'hibp-out');
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -446,6 +446,20 @@ if (isset($_GET['query'])) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "passwordpolicy":
|
||||||
|
switch ($object) {
|
||||||
|
case "html":
|
||||||
|
$password_complexity_rules = password_complexity('html');
|
||||||
|
if ($password_complexity_rules !== false) {
|
||||||
|
process_get_return($password_complexity_rules);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
echo '{}';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case "app-passwd":
|
case "app-passwd":
|
||||||
switch ($object) {
|
switch ($object) {
|
||||||
case "all":
|
case "all":
|
||||||
|
@ -1561,6 +1575,9 @@ if (isset($_GET['query'])) {
|
||||||
case "app_links":
|
case "app_links":
|
||||||
process_edit_return(customize('edit', 'app_links', $attr));
|
process_edit_return(customize('edit', 'app_links', $attr));
|
||||||
break;
|
break;
|
||||||
|
case "passwordpolicy":
|
||||||
|
process_edit_return(password_complexity('edit', $attr));
|
||||||
|
break;
|
||||||
case "relayhost":
|
case "relayhost":
|
||||||
process_edit_return(relayhost('edit', array_merge(array('id' => $items), $attr)));
|
process_edit_return(relayhost('edit', array_merge(array('id' => $items), $attr)));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -234,6 +234,13 @@
|
||||||
"oauth2_revoke_tokens": "Alle Client Tokens entfernen",
|
"oauth2_revoke_tokens": "Alle Client Tokens entfernen",
|
||||||
"optional": "Optional",
|
"optional": "Optional",
|
||||||
"password": "Passwort",
|
"password": "Passwort",
|
||||||
|
"password_length": "Passwortlänge",
|
||||||
|
"password_policy": "Passwortrichtlinie",
|
||||||
|
"password_policy_chars": "Muss ein alphabetisches Zeichen enthalten",
|
||||||
|
"password_policy_length": "Mindestlänge des Passwortes ist %d Zeichen",
|
||||||
|
"password_policy_numbers": "Muss eine Ziffer enthalten",
|
||||||
|
"password_policy_lowerupper": "Muss Großbuchstaben und Kleinbuchstaben enthalten",
|
||||||
|
"password_policy_special_chars": "Muss Sonderzeichen enthalten",
|
||||||
"password_repeat": "Passwort wiederholen",
|
"password_repeat": "Passwort wiederholen",
|
||||||
"priority": "Gewichtung",
|
"priority": "Gewichtung",
|
||||||
"private_key": "Private Key",
|
"private_key": "Private Key",
|
||||||
|
@ -907,6 +914,7 @@
|
||||||
"object_modified": "Änderungen an Objekt %s wurden gespeichert",
|
"object_modified": "Änderungen an Objekt %s wurden gespeichert",
|
||||||
"pushover_settings_edited": "Pushover Konfiguration gespeichert, bitte den Zugang im Anschluss verifizieren.",
|
"pushover_settings_edited": "Pushover Konfiguration gespeichert, bitte den Zugang im Anschluss verifizieren.",
|
||||||
"qlearn_spam": "Nachricht ID %s wurde als Spam gelernt und gelöscht",
|
"qlearn_spam": "Nachricht ID %s wurde als Spam gelernt und gelöscht",
|
||||||
|
"password_policy_saved": "Passwortrichtlinie wurde erfolgreich gespeichert",
|
||||||
"queue_command_success": "Queue-Aufgabe erfolgreich ausgeführt",
|
"queue_command_success": "Queue-Aufgabe erfolgreich ausgeführt",
|
||||||
"recipient_map_entry_deleted": "Empfängerumschreibung mit der ID %s wurde gelöscht",
|
"recipient_map_entry_deleted": "Empfängerumschreibung mit der ID %s wurde gelöscht",
|
||||||
"recipient_map_entry_saved": "Empfängerumschreibung für Objekt \"%s\" wurde gespeichert",
|
"recipient_map_entry_saved": "Empfängerumschreibung für Objekt \"%s\" wurde gespeichert",
|
||||||
|
@ -1027,7 +1035,6 @@
|
||||||
"messages": "Nachrichten",
|
"messages": "Nachrichten",
|
||||||
"never": "Niemals",
|
"never": "Niemals",
|
||||||
"new_password": "Neues Passwort",
|
"new_password": "Neues Passwort",
|
||||||
"new_password_description": "Mindestanforderung: 6 Zeichen lang, Buchstaben und Zahlen.",
|
|
||||||
"new_password_repeat": "Neues Passwort (Wiederholung)",
|
"new_password_repeat": "Neues Passwort (Wiederholung)",
|
||||||
"no_active_filter": "Kein aktiver Filter vorhanden",
|
"no_active_filter": "Kein aktiver Filter vorhanden",
|
||||||
"no_last_login": "Keine letzte UI-Anmeldung gespeichert",
|
"no_last_login": "Keine letzte UI-Anmeldung gespeichert",
|
||||||
|
|
|
@ -232,6 +232,13 @@
|
||||||
"oauth2_revoke_tokens": "Revoke all client tokens",
|
"oauth2_revoke_tokens": "Revoke all client tokens",
|
||||||
"optional": "optional",
|
"optional": "optional",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
|
"password_length": "Password length",
|
||||||
|
"password_policy": "Password policy",
|
||||||
|
"password_policy_chars": "Must contain at least one alphabetic character",
|
||||||
|
"password_policy_length": "Minimum password length is %d",
|
||||||
|
"password_policy_numbers": "Must contain at least one number",
|
||||||
|
"password_policy_lowerupper": "Must contain lowercase and uppercase characters",
|
||||||
|
"password_policy_special_chars": "Must contain special chars",
|
||||||
"password_repeat": "Confirmation password (repeat)",
|
"password_repeat": "Confirmation password (repeat)",
|
||||||
"priority": "Priority",
|
"priority": "Priority",
|
||||||
"private_key": "Private key",
|
"private_key": "Private key",
|
||||||
|
@ -906,6 +913,7 @@
|
||||||
"pushover_settings_edited": "Pushover settings successfully set, please verify credentials.",
|
"pushover_settings_edited": "Pushover settings successfully set, please verify credentials.",
|
||||||
"qlearn_spam": "Message ID %s was learned as spam and deleted",
|
"qlearn_spam": "Message ID %s was learned as spam and deleted",
|
||||||
"queue_command_success": "Queue command completed successfully",
|
"queue_command_success": "Queue command completed successfully",
|
||||||
|
"password_policy_saved": "Password policy was saved successfully",
|
||||||
"recipient_map_entry_deleted": "Recipient map ID %s has been deleted",
|
"recipient_map_entry_deleted": "Recipient map ID %s has been deleted",
|
||||||
"recipient_map_entry_saved": "Recipient map entry \"%s\" has been saved",
|
"recipient_map_entry_saved": "Recipient map entry \"%s\" has been saved",
|
||||||
"relayhost_added": "Map entry %s has been added",
|
"relayhost_added": "Map entry %s has been added",
|
||||||
|
@ -1025,7 +1033,6 @@
|
||||||
"messages": "messages",
|
"messages": "messages",
|
||||||
"never": "Never",
|
"never": "Never",
|
||||||
"new_password": "New password",
|
"new_password": "New password",
|
||||||
"new_password_description": "Requirement: 6 characters long, letters and numbers.",
|
|
||||||
"new_password_repeat": "Confirmation password (repeat)",
|
"new_password_repeat": "Confirmation password (repeat)",
|
||||||
"no_active_filter": "No active filter available",
|
"no_active_filter": "No active filter available",
|
||||||
"no_last_login": "No last UI login information",
|
"no_last_login": "No last UI login information",
|
||||||
|
|
Loading…
Reference in New Issue