[Web] Allow CIDR as allowed API networks; other minor fixes
parent
066b23bb02
commit
aef15f004a
|
@ -113,77 +113,71 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<legend style="margin-top:20px">
|
<legend style="cursor:pointer;" data-target="#admin_api" class="arrow-toggle" unselectable="on" data-toggle="collapse">
|
||||||
<span style="font-size:12px" class="arrow rotate glyphicon glyphicon-wrench"></span> API
|
<span style="font-size:12px" class="arrow rotate glyphicon glyphicon-menu-down"></span> API
|
||||||
</legend>
|
</legend>
|
||||||
|
<div id="admin_api" class="collapse">
|
||||||
<?php
|
<?php
|
||||||
$api_ro = admin_api('ro', 'get');
|
$api_ro = admin_api('ro', 'get');
|
||||||
$api_rw = admin_api('rw', 'get');
|
$api_rw = admin_api('rw', 'get');
|
||||||
?>
|
?>
|
||||||
<div class="panel-group" id="accordion">
|
<div class="col-lg-6">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h4 class="panel-title">
|
<h4 class="panel-title">⇇ Read-Only Access</h4>
|
||||||
<a data-toggle="collapse" data-parent="#accordion" href="#api-ro">
|
</div>
|
||||||
⇇ Read-Only Access</a>
|
<div class="panel-body">
|
||||||
</h4>
|
<form class="form-horizontal" autocapitalize="none" autocorrect="off" role="form" method="post">
|
||||||
</div>
|
<div class="form-group">
|
||||||
<div id="api-ro" class="panel-collapse collapse">
|
<label class="control-label col-sm-3" for="allow_from_ro"><?=$lang['admin']['api_allow_from'];?>:</label>
|
||||||
<div class="panel-body">
|
<div class="col-sm-9">
|
||||||
<form class="form-horizontal" autocapitalize="none" autocorrect="off" role="form" method="post">
|
<textarea class="form-control textarea-code" rows="7" name="allow_from" id="allow_from_ro" <?=($api_ro['skip_ip_check'] == 1) ? 'disabled' : null;?> required><?=htmlspecialchars($api_ro['allow_from']);?></textarea>
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label col-sm-3" for="allow_from_ro"><?=$lang['admin']['api_allow_from'];?>:</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<textarea class="form-control" rows="2" name="allow_from" id="allow_from_ro" <?=($api_ro['skip_ip_check'] == 1) ? 'disabled' : null;?> required><?=htmlspecialchars($api_ro['allow_from']);?></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-sm-offset-3 col-sm-9">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" name="skip_ip_check" id="skip_ip_check_ro" <?=($api_ro['skip_ip_check'] == 1) ? 'checked' : null;?>> <?=$lang['admin']['api_skip_ip_check'];?>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label col-sm-3"><?=$lang['admin']['api_key'];?>:</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<pre><?=(empty(htmlspecialchars($api_ro['api_key']))) ? '-' : htmlspecialchars($api_ro['api_key']);?></pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-sm-offset-3 col-sm-9">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" name="active" <?=($api_ro['active'] == 1) ? 'checked' : null;?>> <?=$lang['admin']['activate_api'];?>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-sm-offset-3 col-sm-9">
|
|
||||||
<p class="help-block"><?=$lang['admin']['api_info'];?></p>
|
|
||||||
<div class="btn-group">
|
|
||||||
<button class="btn btn-sm btn-default" name="admin_api[ro]" type="submit" href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
|
|
||||||
<button class="btn btn-sm btn-primary" name="admin_api_regen_key[ro]" type="submit" href="#"><?=$lang['admin']['regen_api_key'];?></button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="form-group">
|
||||||
</form>
|
<div class="col-sm-offset-3 col-sm-9">
|
||||||
</div>
|
<label>
|
||||||
|
<input type="checkbox" name="skip_ip_check" id="skip_ip_check_ro" <?=($api_ro['skip_ip_check'] == 1) ? 'checked' : null;?>> <?=$lang['admin']['api_skip_ip_check'];?>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-3"><?=$lang['admin']['api_key'];?>:</label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<pre><?=(empty(htmlspecialchars($api_ro['api_key']))) ? '-' : htmlspecialchars($api_ro['api_key']);?></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-3 col-sm-9">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="active" <?=($api_ro['active'] == 1) ? 'checked' : null;?>> <?=$lang['admin']['activate_api'];?>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-3 col-sm-9">
|
||||||
|
<p class="help-block"><?=$lang['admin']['api_info'];?></p>
|
||||||
|
<div class="btn-group">
|
||||||
|
<button class="btn btn-sm btn-success" name="admin_api[ro]" type="submit" href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
|
||||||
|
<button class="btn btn-sm btn-default admin-ays-dialog" name="admin_api_regen_key[ro]" type="submit" href="#"><?=$lang['admin']['regen_api_key'];?></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-lg-6">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h4 class="panel-title">
|
<h4 class="panel-title">⇄ Read-Write Access</h4>
|
||||||
<a data-toggle="collapse" data-parent="#accordion" href="#api-rw">
|
|
||||||
⇄ Read-Write Access</a>
|
|
||||||
</h4>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="api-rw" class="panel-collapse collapse">
|
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<form class="form-horizontal" autocapitalize="none" autocorrect="off" role="form" method="post">
|
<form class="form-horizontal" autocapitalize="none" autocorrect="off" role="form" method="post">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-sm-3" for="allow_from_rw"><?=$lang['admin']['api_allow_from'];?>:</label>
|
<label class="control-label col-sm-3" for="allow_from_rw"><?=$lang['admin']['api_allow_from'];?>:</label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea class="form-control" rows="2" name="allow_from" id="allow_from_rw" <?=($api_rw['skip_ip_check'] == 1) ? 'disabled' : null;?> required><?=htmlspecialchars($api_rw['allow_from']);?></textarea>
|
<textarea class="form-control textarea-code" rows="7" name="allow_from" id="allow_from_rw" <?=($api_rw['skip_ip_check'] == 1) ? 'disabled' : null;?> required><?=htmlspecialchars($api_rw['allow_from']);?></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -210,17 +204,16 @@ if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CAC
|
||||||
<div class="col-sm-offset-3 col-sm-9">
|
<div class="col-sm-offset-3 col-sm-9">
|
||||||
<p class="help-block"><?=$lang['admin']['api_info'];?></p>
|
<p class="help-block"><?=$lang['admin']['api_info'];?></p>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button class="btn btn-sm btn-default" name="admin_api[rw]" type="submit" href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
|
<button class="btn btn-sm btn-success" name="admin_api[rw]" type="submit" href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
|
||||||
<button class="btn btn-sm btn-primary" name="admin_api_regen_key[rw]" type="submit" href="#"><?=$lang['admin']['regen_api_key'];?></button>
|
<button class="btn btn-sm btn-default admin-ays-dialog" name="admin_api_regen_key[rw]" type="submit" href="#"><?=$lang['admin']['regen_api_key'];?></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
function valid_network($network) {
|
|
||||||
$cidr = explode('/', $network);
|
|
||||||
if (filter_var($cidr[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) && (!isset($cidr[1]) || ($cidr[1] >= 0 && $cidr[1] <= 32))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
elseif (filter_var($cidr[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) && (!isset($cidr[1]) || ($cidr[1] >= 0 && $cidr[1] <= 128))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function valid_hostname($hostname) {
|
|
||||||
return filter_var($hostname, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
function fail2ban($_action, $_data = null) {
|
function fail2ban($_action, $_data = null) {
|
||||||
global $redis;
|
global $redis;
|
||||||
global $lang;
|
global $lang;
|
||||||
|
@ -196,6 +181,14 @@ function fail2ban($_action, $_data = null) {
|
||||||
if (valid_network($wl_item) || valid_hostname($wl_item)) {
|
if (valid_network($wl_item) || valid_hostname($wl_item)) {
|
||||||
$redis->hSet('F2B_WHITELIST', $wl_item, 1);
|
$redis->hSet('F2B_WHITELIST', $wl_item, 1);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
'msg' => array('network_host_invalid', $wl_item)
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,6 +199,14 @@ function fail2ban($_action, $_data = null) {
|
||||||
if (valid_network($bl_item) || valid_hostname($bl_item)) {
|
if (valid_network($bl_item) || valid_hostname($bl_item)) {
|
||||||
$redis->hSet('F2B_BLACKLIST', $bl_item, 1);
|
$redis->hSet('F2B_BLACKLIST', $bl_item, 1);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
'msg' => array('network_host_invalid', $bl_item)
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,76 @@ function isset_has_content($var) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Validates ips and cidrs
|
||||||
|
function valid_network($network) {
|
||||||
|
if (filter_var($network, FILTER_VALIDATE_IP)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$parts = explode('/', $network);
|
||||||
|
if (count($parts) != 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$ip = $parts[0];
|
||||||
|
$netmask = $parts[1];
|
||||||
|
if (!preg_match("/^\d+$/", $netmask)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$netmask = intval($parts[1]);
|
||||||
|
if ($netmask < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
||||||
|
return $netmask <= 32;
|
||||||
|
}
|
||||||
|
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||||
|
return $netmask <= 128;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function valid_hostname($hostname) {
|
||||||
|
return filter_var($hostname, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME);
|
||||||
|
}
|
||||||
|
// Thanks to https://stackoverflow.com/a/49373789
|
||||||
|
// Validates exact ip matches and ip-in-cidr, ipv4 and ipv6
|
||||||
|
function ip_acl($ip, $networks) {
|
||||||
|
foreach($networks as $network) {
|
||||||
|
if (filter_var($network, FILTER_VALIDATE_IP)) {
|
||||||
|
if ($ip == $network) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$ipb = inet_pton($ip);
|
||||||
|
$iplen = strlen($ipb);
|
||||||
|
if (strlen($ipb) < 4) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$ar = explode('/', $network);
|
||||||
|
$ip1 = $ar[0];
|
||||||
|
$ip1b = inet_pton($ip1);
|
||||||
|
$ip1len = strlen($ip1b);
|
||||||
|
if ($ip1len != $iplen) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (count($ar)>1) {
|
||||||
|
$bits=(int)($ar[1]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$bits = $iplen * 8;
|
||||||
|
}
|
||||||
|
for ($c=0; $bits>0; $c++) {
|
||||||
|
$bytemask = ($bits < 8) ? 0xff ^ ((1 << (8-$bits))-1) : 0xff;
|
||||||
|
if (((ord($ipb[$c]) ^ ord($ip1b[$c])) & $bytemask) != 0) {
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
$bits-=8;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
function hash_password($password) {
|
function hash_password($password) {
|
||||||
$salt_str = bin2hex(openssl_random_pseudo_bytes(8));
|
$salt_str = bin2hex(openssl_random_pseudo_bytes(8));
|
||||||
return "{SSHA256}".base64_encode(hash('sha256', $password . $salt_str, true) . $salt_str);
|
return "{SSHA256}".base64_encode(hash('sha256', $password . $salt_str, true) . $salt_str);
|
||||||
|
@ -1160,178 +1230,106 @@ function admin_api($access, $action, $data = null) {
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch ($access) {
|
if ($access !== "ro" && $access !== "rw") {
|
||||||
case "rw":
|
$_SESSION['return'][] = array(
|
||||||
switch ($action) {
|
'type' => 'danger',
|
||||||
case "edit":
|
'log' => array(__FUNCTION__),
|
||||||
$active = (isset($data['active'])) ? 1 : 0;
|
'msg' => 'invalid access type'
|
||||||
$skip_ip_check = (isset($data['skip_ip_check'])) ? 1 : 0;
|
);
|
||||||
$allow_from = array_map('trim', preg_split( "/( |,|;|\n)/", $data['allow_from']));
|
return false;
|
||||||
foreach ($allow_from as $key => $val) {
|
}
|
||||||
if (empty($val)) {
|
if ($action == "edit") {
|
||||||
continue;
|
$active = (!empty($data['active'])) ? 1 : 0;
|
||||||
}
|
$skip_ip_check = (isset($data['skip_ip_check'])) ? 1 : 0;
|
||||||
if (!filter_var($val, FILTER_VALIDATE_IP)) {
|
$allow_from = array_map('trim', preg_split( "/( |,|;|\n)/", $data['allow_from']));
|
||||||
$_SESSION['return'][] = array(
|
foreach ($allow_from as $key => $val) {
|
||||||
'type' => 'warning',
|
if (empty($val)) {
|
||||||
'log' => array(__FUNCTION__, $data),
|
unset($allow_from[$key]);
|
||||||
'msg' => array('ip_invalid', htmlspecialchars($allow_from[$key]))
|
continue;
|
||||||
);
|
|
||||||
unset($allow_from[$key]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$allow_from = implode(',', array_unique(array_filter($allow_from)));
|
|
||||||
if (empty($allow_from) && $skip_ip_check == 0) {
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $data),
|
|
||||||
'msg' => 'ip_list_empty'
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$api_key = implode('-', array(
|
|
||||||
strtoupper(bin2hex(random_bytes(3))),
|
|
||||||
strtoupper(bin2hex(random_bytes(3))),
|
|
||||||
strtoupper(bin2hex(random_bytes(3))),
|
|
||||||
strtoupper(bin2hex(random_bytes(3))),
|
|
||||||
strtoupper(bin2hex(random_bytes(3)))
|
|
||||||
));
|
|
||||||
$stmt = $pdo->query("SELECT `api_key` FROM `api` WHERE `access` = 'rw'");
|
|
||||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
|
||||||
if (empty($num_results)) {
|
|
||||||
$stmt = $pdo->prepare("INSERT INTO `api` (`api_key`, `skip_ip_check`, `active`, `allow_from`, `access`)
|
|
||||||
VALUES (:api_key, :skip_ip_check, :active, :allow_from, 'rw');");
|
|
||||||
$stmt->execute(array(
|
|
||||||
':api_key' => $api_key,
|
|
||||||
':skip_ip_check' => $skip_ip_check,
|
|
||||||
':active' => $active,
|
|
||||||
':allow_from' => $allow_from
|
|
||||||
));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ($skip_ip_check == 0) {
|
|
||||||
$stmt = $pdo->prepare("UPDATE `api` SET `skip_ip_check` = :skip_ip_check, `active` = :active, `allow_from` = :allow_from WHERE `access` = 'rw';");
|
|
||||||
$stmt->execute(array(
|
|
||||||
':active' => $active,
|
|
||||||
':skip_ip_check' => $skip_ip_check,
|
|
||||||
':allow_from' => $allow_from
|
|
||||||
));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$stmt = $pdo->prepare("UPDATE `api` SET `skip_ip_check` = :skip_ip_check, `active` = :active WHERE `access` = 'rw';");
|
|
||||||
$stmt->execute(array(
|
|
||||||
':active' => $active,
|
|
||||||
':skip_ip_check' => $skip_ip_check
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "regen_key":
|
|
||||||
$api_key = implode('-', array(
|
|
||||||
strtoupper(bin2hex(random_bytes(3))),
|
|
||||||
strtoupper(bin2hex(random_bytes(3))),
|
|
||||||
strtoupper(bin2hex(random_bytes(3))),
|
|
||||||
strtoupper(bin2hex(random_bytes(3))),
|
|
||||||
strtoupper(bin2hex(random_bytes(3)))
|
|
||||||
));
|
|
||||||
$stmt = $pdo->prepare("UPDATE `api` SET `api_key` = :api_key WHERE `access` = 'rw'");
|
|
||||||
$stmt->execute(array(
|
|
||||||
':api_key' => $api_key
|
|
||||||
));
|
|
||||||
break;
|
|
||||||
case "get":
|
|
||||||
$stmt = $pdo->query("SELECT * FROM `api` WHERE `access` = 'rw'");
|
|
||||||
$apidata = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
||||||
return $apidata;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case "ro":
|
if (valid_network($val) !== true) {
|
||||||
switch ($action) {
|
$_SESSION['return'][] = array(
|
||||||
case "edit":
|
'type' => 'warning',
|
||||||
$active = (isset($data['active'])) ? 1 : 0;
|
'log' => array(__FUNCTION__, $data),
|
||||||
$skip_ip_check = (isset($data['skip_ip_check'])) ? 1 : 0;
|
'msg' => array('ip_invalid', htmlspecialchars($allow_from[$key]))
|
||||||
$allow_from = array_map('trim', preg_split( "/( |,|;|\n)/", $data['allow_from']));
|
);
|
||||||
foreach ($allow_from as $key => $val) {
|
unset($allow_from[$key]);
|
||||||
if (empty($val)) {
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!filter_var($val, FILTER_VALIDATE_IP)) {
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'warning',
|
|
||||||
'log' => array(__FUNCTION__, $data),
|
|
||||||
'msg' => array('ip_invalid', htmlspecialchars($allow_from[$key]))
|
|
||||||
);
|
|
||||||
unset($allow_from[$key]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$allow_from = implode(',', array_unique(array_filter($allow_from)));
|
|
||||||
if (empty($allow_from) && $skip_ip_check == 0) {
|
|
||||||
$_SESSION['return'][] = array(
|
|
||||||
'type' => 'danger',
|
|
||||||
'log' => array(__FUNCTION__, $data),
|
|
||||||
'msg' => 'ip_list_empty'
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$api_key = implode('-', array(
|
|
||||||
strtoupper(bin2hex(random_bytes(3))),
|
|
||||||
strtoupper(bin2hex(random_bytes(3))),
|
|
||||||
strtoupper(bin2hex(random_bytes(3))),
|
|
||||||
strtoupper(bin2hex(random_bytes(3))),
|
|
||||||
strtoupper(bin2hex(random_bytes(3)))
|
|
||||||
));
|
|
||||||
$stmt = $pdo->query("SELECT `api_key` FROM `api` WHERE `access` = 'ro'");
|
|
||||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
|
||||||
if (empty($num_results)) {
|
|
||||||
$stmt = $pdo->prepare("INSERT INTO `api` (`api_key`, `skip_ip_check`, `active`, `allow_from`, `access`)
|
|
||||||
VALUES (:api_key, :skip_ip_check, :active, :allow_from, 'ro');");
|
|
||||||
$stmt->execute(array(
|
|
||||||
':api_key' => $api_key,
|
|
||||||
':skip_ip_check' => $skip_ip_check,
|
|
||||||
':active' => $active,
|
|
||||||
':allow_from' => $allow_from
|
|
||||||
));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ($skip_ip_check == 0) {
|
|
||||||
$stmt = $pdo->prepare("UPDATE `api` SET `skip_ip_check` = :skip_ip_check, `active` = :active, `allow_from` = :allow_from WHERE `access` = 'ro';");
|
|
||||||
$stmt->execute(array(
|
|
||||||
':active' => $active,
|
|
||||||
':skip_ip_check' => $skip_ip_check,
|
|
||||||
':allow_from' => $allow_from
|
|
||||||
));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$stmt = $pdo->prepare("UPDATE `api` SET `skip_ip_check` = :skip_ip_check, `active` = :active WHERE `access` = 'ro';");
|
|
||||||
$stmt->execute(array(
|
|
||||||
':active' => $active,
|
|
||||||
':skip_ip_check' => $skip_ip_check
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "regen_key":
|
|
||||||
$api_key = implode('-', array(
|
|
||||||
strtoupper(bin2hex(random_bytes(3))),
|
|
||||||
strtoupper(bin2hex(random_bytes(3))),
|
|
||||||
strtoupper(bin2hex(random_bytes(3))),
|
|
||||||
strtoupper(bin2hex(random_bytes(3))),
|
|
||||||
strtoupper(bin2hex(random_bytes(3)))
|
|
||||||
));
|
|
||||||
$stmt = $pdo->prepare("UPDATE `api` SET `api_key` = :api_key WHERE `access` = 'ro'");
|
|
||||||
$stmt->execute(array(
|
|
||||||
':api_key' => $api_key
|
|
||||||
));
|
|
||||||
break;
|
|
||||||
case "get":
|
|
||||||
$stmt = $pdo->query("SELECT * FROM `api` WHERE `access` = 'ro'");
|
|
||||||
$apidata = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
||||||
return $apidata;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
$allow_from = implode(',', array_unique(array_filter($allow_from)));
|
||||||
|
if (empty($allow_from) && $skip_ip_check == 0) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $data),
|
||||||
|
'msg' => 'ip_list_empty'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$api_key = implode('-', array(
|
||||||
|
strtoupper(bin2hex(random_bytes(3))),
|
||||||
|
strtoupper(bin2hex(random_bytes(3))),
|
||||||
|
strtoupper(bin2hex(random_bytes(3))),
|
||||||
|
strtoupper(bin2hex(random_bytes(3))),
|
||||||
|
strtoupper(bin2hex(random_bytes(3)))
|
||||||
|
));
|
||||||
|
$stmt = $pdo->query("SELECT `api_key` FROM `api` WHERE `access` = '" . $access . "'");
|
||||||
|
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
|
if (empty($num_results)) {
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `api` (`api_key`, `skip_ip_check`, `active`, `allow_from`, `access`)
|
||||||
|
VALUES (:api_key, :skip_ip_check, :active, :allow_from, :access);");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':api_key' => $api_key,
|
||||||
|
':skip_ip_check' => $skip_ip_check,
|
||||||
|
':active' => $active,
|
||||||
|
':allow_from' => $allow_from,
|
||||||
|
':access' => $access
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ($skip_ip_check == 0) {
|
||||||
|
$stmt = $pdo->prepare("UPDATE `api` SET `skip_ip_check` = :skip_ip_check,
|
||||||
|
`active` = :active,
|
||||||
|
`allow_from` = :allow_from
|
||||||
|
WHERE `access` = :access;");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':active' => $active,
|
||||||
|
':skip_ip_check' => $skip_ip_check,
|
||||||
|
':allow_from' => $allow_from,
|
||||||
|
':access' => $access
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$stmt = $pdo->prepare("UPDATE `api` SET `skip_ip_check` = :skip_ip_check,
|
||||||
|
`active` = :active
|
||||||
|
WHERE `access` = :access;");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':active' => $active,
|
||||||
|
':skip_ip_check' => $skip_ip_check,
|
||||||
|
':access' => $access
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ($action == "regen_key") {
|
||||||
|
$api_key = implode('-', array(
|
||||||
|
strtoupper(bin2hex(random_bytes(3))),
|
||||||
|
strtoupper(bin2hex(random_bytes(3))),
|
||||||
|
strtoupper(bin2hex(random_bytes(3))),
|
||||||
|
strtoupper(bin2hex(random_bytes(3))),
|
||||||
|
strtoupper(bin2hex(random_bytes(3)))
|
||||||
|
));
|
||||||
|
$stmt = $pdo->prepare("UPDATE `api` SET `api_key` = :api_key WHERE `access` = :access");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':api_key' => $api_key,
|
||||||
|
':access' => $access
|
||||||
|
));
|
||||||
|
}
|
||||||
|
elseif ($action == "get") {
|
||||||
|
$stmt = $pdo->query("SELECT * FROM `api` WHERE `access` = '" . $access . "'");
|
||||||
|
$apidata = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$apidata['allow_from'] = str_replace(',', PHP_EOL, $apidata['allow_from']);
|
||||||
|
return $apidata;
|
||||||
}
|
}
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
|
|
|
@ -179,6 +179,8 @@ function get_remote_ip($anonymize = null) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load core functions first
|
||||||
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.inc.php';
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/sessions.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/sessions.inc.php';
|
||||||
|
|
||||||
// IMAP lib
|
// IMAP lib
|
||||||
|
@ -215,7 +217,6 @@ if(file_exists($langFile)) {
|
||||||
$lang = array_merge_real($lang, json_decode(file_get_contents($langFile), true));
|
$lang = array_merge_real($lang, json_decode(file_get_contents($langFile), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.inc.php';
|
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.acl.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.acl.inc.php';
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.app_passwd.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.app_passwd.inc.php';
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.mailbox.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.mailbox.inc.php';
|
||||||
|
|
|
@ -53,7 +53,7 @@ if (!empty($_SERVER['HTTP_X_API_KEY'])) {
|
||||||
$skip_ip_check = ($api_return['skip_ip_check'] == 1);
|
$skip_ip_check = ($api_return['skip_ip_check'] == 1);
|
||||||
$remote = get_remote_ip(false);
|
$remote = get_remote_ip(false);
|
||||||
$allow_from = array_map('trim', preg_split( "/( |,|;|\n)/", $api_return['allow_from']));
|
$allow_from = array_map('trim', preg_split( "/( |,|;|\n)/", $api_return['allow_from']));
|
||||||
if (in_array($remote, $allow_from) || $skip_ip_check === true) {
|
if ($skip_ip_check === true || ip_acl($remote, $allow_from)) {
|
||||||
$_SESSION['mailcow_cc_username'] = 'API';
|
$_SESSION['mailcow_cc_username'] = 'API';
|
||||||
$_SESSION['mailcow_cc_role'] = 'admin';
|
$_SESSION['mailcow_cc_role'] = 'admin';
|
||||||
$_SESSION['mailcow_cc_api'] = true;
|
$_SESSION['mailcow_cc_api'] = true;
|
||||||
|
|
|
@ -21,6 +21,7 @@ jQuery(function($){
|
||||||
$("#mass_exclude").change(function(){ $("#mass_include").selectpicker('deselectAll'); });
|
$("#mass_exclude").change(function(){ $("#mass_include").selectpicker('deselectAll'); });
|
||||||
$("#mass_include").change(function(){ $("#mass_exclude").selectpicker('deselectAll'); });
|
$("#mass_include").change(function(){ $("#mass_exclude").selectpicker('deselectAll'); });
|
||||||
$("#mass_disarm").click(function() { $("#mass_send").attr("disabled", !this.checked); });
|
$("#mass_disarm").click(function() { $("#mass_send").attr("disabled", !this.checked); });
|
||||||
|
$(".admin-ays-dialog").click(function() { return confirm(lang.ays); });
|
||||||
$(".validate_rspamd_regex").click(function( event ) {
|
$(".validate_rspamd_regex").click(function( event ) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
var regex_map_id = $(this).data('regex-map');
|
var regex_map_id = $(this).data('regex-map');
|
||||||
|
|
|
@ -122,7 +122,7 @@
|
||||||
"admin_details": "Administrator bearbeiten",
|
"admin_details": "Administrator bearbeiten",
|
||||||
"admin_domains": "Domain-Zuweisungen",
|
"admin_domains": "Domain-Zuweisungen",
|
||||||
"advanced_settings": "Erweiterte Einstellungen",
|
"advanced_settings": "Erweiterte Einstellungen",
|
||||||
"api_allow_from": "IP-Adressen für Zugriff",
|
"api_allow_from": "IP-Adressen oder Netzwerke (CIDR Notation) für Zugriff auf API",
|
||||||
"api_info": "Das API befindet sich noch in Entwicklung, die Dokumentation kann unter <a href=\"/api\">/api</a> abgerufen werden.",
|
"api_info": "Das API befindet sich noch in Entwicklung, die Dokumentation kann unter <a href=\"/api\">/api</a> abgerufen werden.",
|
||||||
"api_key": "API-Key",
|
"api_key": "API-Key",
|
||||||
"api_skip_ip_check": "IP-Check für API nicht ausführen",
|
"api_skip_ip_check": "IP-Check für API nicht ausführen",
|
||||||
|
@ -131,6 +131,7 @@
|
||||||
"apps_name": "\"mailcow Apps\" Name",
|
"apps_name": "\"mailcow Apps\" Name",
|
||||||
"arrival_time": "Ankunftszeit (Serverzeit)",
|
"arrival_time": "Ankunftszeit (Serverzeit)",
|
||||||
"authed_user": "Auth. Benutzer",
|
"authed_user": "Auth. Benutzer",
|
||||||
|
"ays": "Soll der Vorgang wirklich ausgeführt werden?",
|
||||||
"ban_list_info": "Übersicht ausgesperrter Netzwerke: <b>Netzwerk (verbleibende Banzeit) - [Aktionen]</b>.<br />IPs, die zum Entsperren eingereiht werden, verlassen die Liste aktiver Bans nach wenigen Sekunden.<br />Rote Labels sind Indikatoren für aktive Blacklisteinträge.",
|
"ban_list_info": "Übersicht ausgesperrter Netzwerke: <b>Netzwerk (verbleibende Banzeit) - [Aktionen]</b>.<br />IPs, die zum Entsperren eingereiht werden, verlassen die Liste aktiver Bans nach wenigen Sekunden.<br />Rote Labels sind Indikatoren für aktive Blacklisteinträge.",
|
||||||
"change_logo": "Logo ändern",
|
"change_logo": "Logo ändern",
|
||||||
"configuration": "Konfiguration",
|
"configuration": "Konfiguration",
|
||||||
|
|
|
@ -122,7 +122,7 @@
|
||||||
"admin_details": "Edit administrator details",
|
"admin_details": "Edit administrator details",
|
||||||
"admin_domains": "Domain assignments",
|
"admin_domains": "Domain assignments",
|
||||||
"advanced_settings": "Advanced settings",
|
"advanced_settings": "Advanced settings",
|
||||||
"api_allow_from": "Allow API access from these IPs (separated by comma or new line)",
|
"api_allow_from": "Allow API access from these IPs/CIDR network notations",
|
||||||
"api_info": "The API is a work in progress. The documentation can be found at <a href=\"/api\">/api</a>",
|
"api_info": "The API is a work in progress. The documentation can be found at <a href=\"/api\">/api</a>",
|
||||||
"api_key": "API key",
|
"api_key": "API key",
|
||||||
"api_skip_ip_check": "Skip IP check for API",
|
"api_skip_ip_check": "Skip IP check for API",
|
||||||
|
@ -131,6 +131,7 @@
|
||||||
"apps_name": "\"mailcow Apps\" name",
|
"apps_name": "\"mailcow Apps\" name",
|
||||||
"arrival_time": "Arrival time (server time)",
|
"arrival_time": "Arrival time (server time)",
|
||||||
"authed_user": "Auth. user",
|
"authed_user": "Auth. user",
|
||||||
|
"ays": "Are you sure you want to proceed?",
|
||||||
"ban_list_info": "See a list of banned IPs below: <b>network (remaining ban time) - [actions]</b>.<br />IPs queued to be unbanned will be removed from the active ban list within a few seconds.<br />Red labels indicate active permanent bans by blacklisting.",
|
"ban_list_info": "See a list of banned IPs below: <b>network (remaining ban time) - [actions]</b>.<br />IPs queued to be unbanned will be removed from the active ban list within a few seconds.<br />Red labels indicate active permanent bans by blacklisting.",
|
||||||
"change_logo": "Change logo",
|
"change_logo": "Change logo",
|
||||||
"configuration": "Configuration",
|
"configuration": "Configuration",
|
||||||
|
|
Loading…
Reference in New Issue