started UI api-key management

Signed-off-by: Michael Kaufmann (d00p) <d00p@froxlor.org>
This commit is contained in:
Michael Kaufmann (d00p)
2018-03-04 12:40:47 +01:00
parent 702b52d13e
commit b07d6ceeaa
13 changed files with 299 additions and 12 deletions

View File

@@ -393,6 +393,9 @@ if ($page == 'overview') {
redirectTo($filename, array('s' => $s));
}
}
elseif ($page == 'apikeys' && Settings::Get('api.enabled') == 1) {
require_once __DIR__ . '/api_keys.php';
}
elseif ($page == 'apihelp' && Settings::Get('api.enabled') == 1) {
require_once __DIR__ . '/apihelp.php';
}

128
api_keys.php Normal file
View File

@@ -0,0 +1,128 @@
<?php
if (! defined('AREA')) {
header("Location: index.php");
exit();
}
/**
* This file is part of the Froxlor project.
* Copyright (c) 2018 the Froxlor Team (see authors).
*
* For the full copyright and license information, please view the COPYING
* file that was distributed with this source code. You can also view the
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
*
* @copyright (c) the authors
* @author Froxlor team <team@froxlor.org> (2018-)
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
* @package Panel
* @since 0.10.0
*
*/
// This file is being included in admin_index and customer_index
// and therefore does not need to require lib/init.php
$log->logAction(USR_ACTION, LOG_NOTICE, "viewed api::api_keys");
// select all my (accessable) certificates
$keys_stmt_query = "SELECT ak.*, c.loginname, a.loginname as adminname
FROM `" . TABLE_API_KEYS . "` ak
LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` c ON `c`.`customerid` = `ak`.`customerid`
LEFT JOIN `" . TABLE_PANEL_ADMINS . "` a ON `a`.`adminid` = `ak`.`adminid`
WHERE ";
$qry_params = array();
if (AREA == 'admin' && $userinfo['customers_see_all'] == '0') {
// admin with only customer-specific permissions
$keys_stmt_query .= "ak.adminid = :adminid ";
$qry_params['adminid'] = $userinfo['adminid'];
$fields = array(
'a.loginname' => $lng['login']['username']
);
} elseif (AREA == 'customer') {
// customer-area
$keys_stmt_query .= "ak.customerid = :cid ";
$qry_params['cid'] = $userinfo['customerid'];
$fields = array(
'c.loginname' => $lng['login']['username']
);
} else {
// admin who can see all customers / reseller / admins
$keys_stmt_query .= "1 ";
$fields = array(
'a.loginname' => $lng['login']['username']
);
}
$paging = new paging($userinfo, TABLE_API_KEYS, $fields);
$keys_stmt_query .= $paging->getSqlWhere(true) . " " . $paging->getSqlOrderBy() . " " . $paging->getSqlLimit();
$keys_stmt = Database::prepare($keys_stmt_query);
Database::pexecute($keys_stmt, $qry_params);
$all_keys = $keys_stmt->fetchAll(PDO::FETCH_ASSOC);
$apikeys = "";
if (count($all_keys) == 0) {
$count = 0;
$message = $lng['apikeys']['no_api_keys'];
$sortcode = "";
$searchcode = "";
$pagingcode = "";
eval("\$apikeys.=\"" . getTemplate("api_keys/keys_error", true) . "\";");
} else {
$count = count($all_keys);
$paging->setEntries($count);
$sortcode = $paging->getHtmlSortCode($lng);
$arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s);
$searchcode = $paging->getHtmlSearchCode($lng);
$pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s);
foreach ($all_keys as $idx => $key) {
if ($paging->checkDisplay($idx)) {
// my own key
$isMyKey = false;
if ($key['adminid'] == $userinfo['adminid'] && (AREA == 'admin' || (AREA == 'customer' && $key['customerid'] == $userinfo['customerid']))) {
// this is mine
$isMyKey = true;
}
$adminCustomerLink = "";
if (AREA == 'admin') {
if ($isMyKey) {
$adminCustomerLink = $key['adminname'];
} else {
$adminCustomerLink = '&nbsp;(<a href="' . $linker->getLink(array(
'section' => (empty($key['customerid']) ? 'admins' : 'customers'),
'page' => (empty($key['customerid']) ? 'admins' : 'customers'),
'action' => 'su',
'id' => (empty($key['customerid']) ? $key['adminid'] : $key['customerid'])
)) . '" rel="external">' . (empty($key['customerid']) ? $key['adminname'] : $key['loginname']) . '</a>)';
}
} else {
// customer do not need links
$adminCustomerLink = $key['loginname'];
}
// escape stuff
$row = htmlentities_array($key);
// check whether the api key is not valid anymore
$isValid = true;
if ($row['valid_until'] >= 0) {
if ($row['valid_until'] < time()) {
$isValid = false;
}
// format
$row['valid_until'] = date('d.m.Y H:i', $row['valid_until']);
} else {
$row['valid_until'] = "&infin;";
}
eval("\$apikeys.=\"" . getTemplate("api_keys/keys_key", true) . "\";");
} else {
continue;
}
}
}
eval("echo \"" . getTemplate("api_keys/keys_list", true) . "\";");

View File

@@ -314,6 +314,9 @@ if ($page == 'overview') {
redirectTo($filename, array('s' => $s));
}
}
elseif ($page == 'apikeys' && Settings::Get('api.enabled') == 1) {
require_once __DIR__ . '/api_keys.php';
}
elseif ($page == 'apihelp' && Settings::Get('api.enabled') == 1) {
require_once __DIR__ . '/apihelp.php';
}

View File

@@ -595,27 +595,31 @@ class Admins extends ApiCommand implements ResourceEntity
standard_error('youcantdeleteyourself', '', true);
}
// delete admin
$del_stmt = Database::prepare("
DELETE FROM `" . TABLE_PANEL_ADMINS . "` WHERE `adminid` = :adminid
");
Database::pexecute($del_stmt, array(
'adminid' => $id
), true, true);
// delete the traffic-usage
$del_stmt = Database::prepare("
DELETE FROM `" . TABLE_PANEL_TRAFFIC_ADMINS . "` WHERE `adminid` = :adminid
");
Database::pexecute($del_stmt, array(
'adminid' => $id
), true, true);
// delete the diskspace usage
$del_stmt = Database::prepare("
DELETE FROM `" . TABLE_PANEL_DISKSPACE_ADMINS . "` WHERE `adminid` = :adminid
");
Database::pexecute($del_stmt, array(
'adminid' => $id
), true, true);
// set admin-id of the old admin's customer to current admins
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_CUSTOMERS . "` SET
`adminid` = :userid WHERE `adminid` = :adminid
@@ -624,7 +628,8 @@ class Admins extends ApiCommand implements ResourceEntity
'userid' => $this->getUserDetail('adminid'),
'adminid' => $id
), true, true);
// set admin-id of the old admin's domains to current admins
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_DOMAINS . "` SET
`adminid` = :userid WHERE `adminid` = :adminid
@@ -633,7 +638,26 @@ class Admins extends ApiCommand implements ResourceEntity
'userid' => $this->getUserDetail('adminid'),
'adminid' => $id
), true, true);
// delete old admin's api keys if exists (no customer keys)
$upd_stmt = Database::prepare("
DELETE FROM `" . TABLE_API_KEYS . "` WHERE
`adminid` = :userid AND `customerid` = '0'
");
Database::pexecute($upd_stmt, array(
'adminid' => $id
), true, true);
// set admin-id of the old admin's api-keys to current admins
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_API_KEYS . "` SET
`adminid` = :userid WHERE `adminid` = :adminid
");
Database::pexecute($upd_stmt, array(
'userid' => $this->getUserDetail('adminid'),
'adminid' => $id
), true, true);
$this->logger()->logAction(ADM_ACTION, LOG_WARNING, "[API] deleted admin '" . $result['loginname'] . "'");
updateCounters();
return $this->response(200, "successfull", $result);

View File

@@ -857,9 +857,9 @@ class Customers extends ApiCommand implements ResourceEntity
// activate/deactivate customer services
if ($deactivated != $result['deactivated']) {
$yesno = (($deactivated) ? 'N' : 'Y');
$pop3 = (($deactivated) ? '0' : (int) $result['pop3']);
$imap = (($deactivated) ? '0' : (int) $result['imap']);
$yesno = ($deactivated ? 'N' : 'Y');
$pop3 = ($deactivated ? '0' : (int) $result['pop3']);
$imap = ($deactivated ? '0' : (int) $result['imap']);
$upd_stmt = Database::prepare("
UPDATE `" . TABLE_MAIL_USERS . "` SET `postfix`= :yesno, `pop3` = :pop3, `imap` = :imap WHERE `customerid` = :customerid
@@ -923,8 +923,16 @@ class Customers extends ApiCommand implements ResourceEntity
// At last flush the new privileges
$dbm->getManager()->flushPrivileges();
Database::needRoot(false);
$this->logger()->logAction(ADM_ACTION, LOG_INFO, "[API] deactivated user '" . $result['loginname'] . "'");
// reactivate/deactivate api-keys
$valid_until = $deactivated ? 0 : - 1;
$stmt = Database::prepare("UPDATE `" . TABLE_API_KEYS . "` SET `valid_until` = :vu WHERE `customerid` = :id");
Database::pexecute($stmt, array(
'id' => $id,
'vu' => $valid_until
), true, true);
$this->logger()->logAction(ADM_ACTION, LOG_INFO, "[API] " . ($deactivated ? 'deactivated' : 'reactivated') . " user '" . $result['loginname'] . "'");
inserttask('1');
}
@@ -1323,6 +1331,12 @@ class Customers extends ApiCommand implements ResourceEntity
'id' => $id
), true, true);
// remove api-keys
$stmt = Database::prepare("DELETE FROM `" . TABLE_API_KEYS . "` WHERE `customerid` = :id");
Database::pexecute($stmt, array(
'id' => $id
), true, true);
// Delete all waiting "create user" -tasks for this user, #276
// Note: the WHERE selects part of a serialized array, but it should be safe this way
$del_stmt = Database::prepare("

View File

@@ -38,6 +38,11 @@ return array(
'label' => $lng['menue']['main']['changetheme'],
'show_element' => (Settings::Get('panel.allow_theme_change_customer') == true)
),
array(
'url' => 'customer_index.php?page=apikeys',
'label' => $lng['menue']['main']['apikeys'],
'show_element' => (Settings::Get('api.enabled') == true)
),
array(
'url' => 'customer_index.php?page=apihelp',
'label' => $lng['menue']['main']['apihelp'],
@@ -184,6 +189,11 @@ return array(
'label' => $lng['menue']['main']['changetheme'],
'show_element' => (Settings::Get('panel.allow_theme_change_admin') == true)
),
array(
'url' => 'admin_index.php?page=apikeys',
'label' => $lng['menue']['main']['apikeys'],
'show_element' => (Settings::Get('api.enabled') == true)
),
array(
'url' => 'admin_index.php?page=apihelp',
'label' => $lng['menue']['main']['apihelp'],

View File

@@ -2123,3 +2123,6 @@ $lng['admin']['notryfiles']['description'] = 'Say yes here if you want to specif
// added in froxlor 0.10.0
$lng['panel']['none_value'] = 'None';
$lng['menue']['main']['apihelp'] = 'API help';
$lng['menue']['main']['apikeys'] = 'API keys';
$lng['apikeys']['no_api_keys'] = 'No API keys found';
$lng['apikeys']['key_add'] = 'Add new key';

View File

@@ -1773,3 +1773,6 @@ $lng['admin']['notryfiles']['description'] = 'Wähle "Ja", wenn eine eigene try_
// added in froxlor 0.10.0
$lng['panel']['none_value'] = 'Keine';
$lng['menue']['main']['apihelp'] = 'API Hilfe';
$lng['menue']['main']['apikeys'] = 'API Keys';
$lng['apikeys']['no_api_keys'] = 'Keine API Keys gefunden';
$lng['apikeys']['key_add'] = 'API Key hinzufügen';

View File

@@ -0,0 +1,3 @@
<tr>
<td colspan="6"><span class="red">{$message}</span></td>
</tr>

27
templates/Sparkle/api_keys/keys_key.tpl vendored Normal file
View File

@@ -0,0 +1,27 @@
<tr <if $isMyKey>class="primary-entry"</if>>
<td>
{$adminCustomerLink}
</td>
<td>
{$row['apikey']}
</td>
<td>
{$row['secret']}
</td>
<td>
{$row['allowed_from']}
</td>
<td>
<if !$isValid><strong><span class="red"></if>
{$row['valid_until']}
<if !$isValid></span></strong></if>
</td>
<td>
<a href="{$linker->getLink(array('section' => 'index', 'page' => $page, 'action' => 'edit', 'id' => $row['id']))}">
<img src="templates/{$theme}/assets/img/icons/edit.png" alt="{$lng['panel']['edit']}" title="{$lng['panel']['edit']}" />
</a>&nbsp;
<a href="{$linker->getLink(array('section' => 'index', 'page' => $page, 'action' => 'delete', 'id' => $row['id']))}">
<img src="templates/{$theme}/assets/img/icons/delete.png" alt="{$lng['panel']['delete']}" title="{$lng['panel']['delete']}" />
</a>
</td>
</tr>

View File

@@ -0,0 +1,68 @@
$header
<article>
<header>
<h2>
<img src="templates/{$theme}/assets/img/icons/lock_big.png" alt="" />&nbsp;
{$lng['menue']['main']['apikeys']}
</h2>
</header>
<if !empty($success_message)>
<div class="successcontainer bradius">
<div class="successtitle">{$lng['success']['success']}</div>
<div class="success">
$success_message
</div>
</div>
</if>
<section>
<form action="{$linker->getLink(array('section' => 'index', 'page' => $page))}" method="post" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="s" value="$s" />
<input type="hidden" name="page" value="$page" />
<div class="overviewsearch">
{$searchcode}
</div>
<div class="overviewadd">
<img src="templates/{$theme}/assets/img/icons/add.png" alt="" />
<a href="{$linker->getLink(array('section' => 'index', 'page' => $page, 'action' => 'add'))}">{$lng['apikeys']['key_add']}</a>
</div>
<table class="full hl">
<thead>
<tr>
<th>User</th>
<th>API-keys</th>
<th>Secret</th>
<th>Allowed from</th>
<th>Valid until</th>
<th>{$lng['panel']['options']}</th>
</tr>
</thead>
<if $pagingcode != ''>
<tfoot>
<tr>
<td colspan="6">{$pagingcode}</td>
</tr>
</tfoot>
</if>
<tbody>
{$apikeys}
</tbody>
</table>
</form>
<if 15 < $count >
<div class="overviewadd">
<img src="templates/{$theme}/assets/img/icons/add.png" alt="" />
<a href="{$linker->getLink(array('section' => 'index', 'page' => $page, 'action' => 'add'))}">{$lng['apikeys']['key_add']}</a>
</div>
</if>
</section>
</article>
$footer

View File

@@ -1682,13 +1682,13 @@ fieldset.file {
background-color: rgb(242, 222, 222);
}
.domain-hostname {
.primary-entry {
background-color: rgb(53, 106, 160);
color: #ddd;
font-weight: bold;
}
table.hl tbody tr.domain-hostname:hover {
table.hl tbody tr.primary-entry:hover {
background-color: rgb(64, 150, 238);
}

View File

@@ -68,6 +68,7 @@
<li><a href="{$linker->getLink(array('section' => 'index', 'page' => 'change_theme'))}">{$lng['panel']['theme']}</a></li>
</if>
<if Settings::Get('api.enabled') == 1>
<li><a href="{$linker->getLink(array('section' => 'index', 'page' => 'apikeys'))}">{$lng['menue']['main']['apikeys']}</a></li>
<li><a href="{$linker->getLink(array('section' => 'index', 'page' => 'apihelp'))}">{$lng['menue']['main']['apihelp']}</a></li>
</if>
</ul>