mirror of
https://github.com/nuxsmin/sysPass.git
synced 2026-03-24 09:07:18 +01:00
* [MOD] Improved API auth security. There is no need to provide the user's password, it will ask for a token password when generating it.
This commit is contained in:
@@ -81,7 +81,11 @@ function debugLog($data, $printLastCaller = false)
|
||||
|
||||
for ($i = 1; $i <= $n - 1; $i++) {
|
||||
$class = isset($backtrace[$i]['class']) ? $backtrace[$i]['class'] : '';
|
||||
error_log(sprintf('Caller %d: %s\%s', $i, $class, $backtrace[$i]['function']));
|
||||
$line = sprintf('Caller %d: %s\%s', $i, $class, $backtrace[$i]['function']);
|
||||
|
||||
if (!error_log($line . PHP_EOL, 3, LOG_FILE)) {
|
||||
error_log($line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
/**
|
||||
* sysPass
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link http://syspass.org
|
||||
* @author nuxsmin
|
||||
* @link http://syspass.org
|
||||
* @copyright 2012-2017, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
@@ -26,18 +26,18 @@ namespace SP\Api;
|
||||
|
||||
defined('APP_ROOT') || die();
|
||||
|
||||
use SP\Auth\Auth;
|
||||
use SP\Auth\AuthResult;
|
||||
use SP\Auth\AuthUtil;
|
||||
use Defuse\Crypto\Exception\CryptoException;
|
||||
use SP\Core\Crypt\Crypt;
|
||||
use SP\Core\Crypt\Hash;
|
||||
use SP\Core\Exceptions\InvalidArgumentException;
|
||||
use SP\Core\Exceptions\SPException;
|
||||
use SP\Core\Session;
|
||||
use SP\Core\SessionUtil;
|
||||
use SP\DataModel\UserData;
|
||||
use SP\DataModel\ApiTokenData;
|
||||
use SP\DataModel\UserLoginData;
|
||||
use SP\Log\Log;
|
||||
use SP\Mgmt\ApiTokens\ApiToken;
|
||||
use SP\Mgmt\Users\User;
|
||||
use SP\Mgmt\Users\UserPass;
|
||||
use SP\Util\Json;
|
||||
|
||||
/**
|
||||
@@ -71,10 +71,6 @@ abstract class ApiBase implements ApiInterface
|
||||
* @var mixed
|
||||
*/
|
||||
protected $data;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $mPass = '';
|
||||
/**
|
||||
* @var UserLoginData
|
||||
*/
|
||||
@@ -83,6 +79,10 @@ abstract class ApiBase implements ApiInterface
|
||||
* @var Log
|
||||
*/
|
||||
protected $Log;
|
||||
/**
|
||||
* @var ApiTokenData
|
||||
*/
|
||||
protected $ApiTokenData;
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
@@ -91,18 +91,19 @@ abstract class ApiBase implements ApiInterface
|
||||
public function __construct($data)
|
||||
{
|
||||
$this->actionId = $this->getActionId($data->method);
|
||||
$this->ApiTokenData = ApiToken::getItem()->getTokenByToken($this->actionId, $data->params->authToken);
|
||||
|
||||
if (!AuthUtil::checkAuthToken($this->actionId, $data->params->authToken)) {
|
||||
if ($this->ApiTokenData === false) {
|
||||
throw new SPException(SPException::SP_CRITICAL, __('Acceso no permitido', false));
|
||||
}
|
||||
|
||||
$this->data = $data;
|
||||
|
||||
$this->userId = ApiTokensUtil::getUserIdForToken($data->params->authToken);
|
||||
$this->userId = $this->ApiTokenData->getAuthtokenUserId();
|
||||
|
||||
$this->loadUserData();
|
||||
|
||||
if ($this->getParam('userPass') !== null) {
|
||||
if ($this->getParam('pass') !== null) {
|
||||
$this->doAuth();
|
||||
}
|
||||
|
||||
@@ -127,17 +128,11 @@ abstract class ApiBase implements ApiInterface
|
||||
/**
|
||||
* Cargar los datos del usuario
|
||||
*
|
||||
* @return UserData
|
||||
* @throws \SP\Core\Exceptions\InvalidClassException
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
protected function loadUserData()
|
||||
{
|
||||
$UserData = new UserData();
|
||||
$UserData->setUserId($this->userId);
|
||||
$UserData->setUserPass($this->getParam('userPass'));
|
||||
|
||||
$this->UserData = User::getItem($UserData)->getById($this->userId);
|
||||
$this->UserData = User::getItem()->getById($this->ApiTokenData->getAuthtokenUserId());
|
||||
|
||||
SessionUtil::loadUserSession($this->UserData);
|
||||
}
|
||||
@@ -145,9 +140,9 @@ abstract class ApiBase implements ApiInterface
|
||||
/**
|
||||
* Devolver el valor de un parámetro
|
||||
*
|
||||
* @param string $name Nombre del parámetro
|
||||
* @param bool $required Si es requerido
|
||||
* @param mixed $default Valor por defecto
|
||||
* @param string $name Nombre del parámetro
|
||||
* @param bool $required Si es requerido
|
||||
* @param mixed $default Valor por defecto
|
||||
* @return int|string
|
||||
* @throws SPException
|
||||
*/
|
||||
@@ -168,36 +163,30 @@ abstract class ApiBase implements ApiInterface
|
||||
* Realizar la autentificación del usuario
|
||||
*
|
||||
* @throws SPException
|
||||
* @throws \SP\Core\Exceptions\InvalidClassException
|
||||
* @throws \Defuse\Crypto\Exception\BadFormatException
|
||||
* @throws \Defuse\Crypto\Exception\CryptoException
|
||||
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
|
||||
*/
|
||||
protected function doAuth()
|
||||
{
|
||||
$Auth = new Auth($this->UserData);
|
||||
$resAuth = $Auth->doAuth();
|
||||
|
||||
if ($resAuth !== false) {
|
||||
/** @var AuthResult $AuthResult */
|
||||
foreach ($resAuth as $AuthResult) {
|
||||
$data = $AuthResult->getData();
|
||||
|
||||
if ($data->getAuthenticated() && $data->getStatusCode() === 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($this->UserData->isUserIsDisabled()
|
||||
|| !Hash::checkHashKey($this->getParam('pass'), $this->ApiTokenData->getAuthtokenHash())
|
||||
) {
|
||||
throw new SPException(SPException::SP_CRITICAL, __('Acceso no permitido', false));
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->UserData->isUserIsDisabled()
|
||||
&& UserPass::loadUserMPass($this->UserData) === UserPass::MPASS_OK
|
||||
) {
|
||||
$this->auth = true;
|
||||
$this->mPass = UserPass::getClearUserMPass();
|
||||
} else {
|
||||
throw new SPException(SPException::SP_CRITICAL, __('Acceso no permitido', false));
|
||||
/**
|
||||
* Devolver la clave maestra
|
||||
*
|
||||
* @return string
|
||||
* @throws SPException
|
||||
*/
|
||||
protected function getMPass()
|
||||
{
|
||||
try {
|
||||
$key = $this->getParam('pass') . $this->getParam('authToken');
|
||||
$securedKey = Crypt::unlockSecuredKey($this->ApiTokenData->getAuthtokenKey(), $key);
|
||||
return Crypt::decrypt($this->ApiTokenData->getAuthtokenPass(), $securedKey, $key);
|
||||
} catch (CryptoException $e) {
|
||||
throw new SPException(SPException::SP_ERROR, __('Error interno', false), $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,314 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* sysPass
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link http://syspass.org
|
||||
* @copyright 2012-2017, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
* sysPass is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sysPass is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace SP\Api;
|
||||
|
||||
defined('APP_ROOT') || die();
|
||||
|
||||
use SP\Core\Exceptions\SPException;
|
||||
use SP\Core\Session;
|
||||
use SP\Storage\DB;
|
||||
use SP\Storage\QueryData;
|
||||
|
||||
/**
|
||||
* Class ApiTokens para la gestión de autorizaciones de acceso a la API de sysPass
|
||||
*
|
||||
* @package SP
|
||||
*/
|
||||
class ApiTokens
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $tokenId = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $userId = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $actionId = 0;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $token = '';
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $refreshToken = false;
|
||||
|
||||
/**
|
||||
* @param boolean $refreshToken
|
||||
*/
|
||||
public function setRefreshToken($refreshToken)
|
||||
{
|
||||
$this->refreshToken = $refreshToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Añadir un nuevo token
|
||||
*
|
||||
* @throws SPException
|
||||
*/
|
||||
public function addToken()
|
||||
{
|
||||
$this->checkTokenExist();
|
||||
|
||||
if ($this->refreshToken) {
|
||||
$this->refreshToken();
|
||||
}
|
||||
|
||||
$query = /** @lang SQL */
|
||||
'INSERT INTO authTokens
|
||||
SET authtoken_userId = :userid,
|
||||
authtoken_actionId = :actionid,
|
||||
authtoken_createdBy = :createdby,
|
||||
authtoken_token = :token,
|
||||
authtoken_startDate = UNIX_TIMESTAMP()';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($this->userId, 'userid');
|
||||
$Data->addParam($this->actionId, 'actionid');
|
||||
$Data->addParam(Session::getUserData()->getUserId(), 'createdby');
|
||||
$Data->addParam($this->getUserToken() ? $this->token : $this->generateToken(), 'token');
|
||||
$Data->setOnErrorMessage(__('Error interno', false));
|
||||
|
||||
DB::getQuery($Data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Comprobar si el token ya existe
|
||||
*
|
||||
* @return bool
|
||||
* @throws SPException
|
||||
*/
|
||||
private function checkTokenExist()
|
||||
{
|
||||
$query = /** @lang SQL */
|
||||
'SELECT authtoken_id FROM authTokens
|
||||
WHERE authtoken_userId = :userid
|
||||
AND authtoken_actionId = :actionid
|
||||
AND authtoken_id <> :id LIMIT 1';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($this->tokenId, 'id');
|
||||
$Data->addParam($this->userId, 'userid');
|
||||
$Data->addParam($this->actionId, 'actionid');
|
||||
|
||||
try {
|
||||
DB::getResults($Data);
|
||||
} catch (SPException $e) {
|
||||
throw new SPException(SPException::SP_CRITICAL, __('Error interno', false));
|
||||
}
|
||||
|
||||
if ($Data->getQueryNumRows() === 1) {
|
||||
throw new SPException(SPException::SP_WARNING, __('La autorización ya existe', false));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerar el hash de los tokens de un usuario
|
||||
*
|
||||
* @throws SPException
|
||||
*/
|
||||
private function refreshToken()
|
||||
{
|
||||
$query = /** @lang SQL */
|
||||
'UPDATE authTokens SET
|
||||
authtoken_token = :token,
|
||||
authtoken_startDate = UNIX_TIMESTAMP()
|
||||
WHERE authtoken_userId = :userid';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($this->userId, 'userid');
|
||||
$Data->addParam($this->generateToken(), 'token');
|
||||
$Data->setOnErrorMessage(__('Error interno', false));
|
||||
|
||||
DB::getQuery($Data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generar un token de acceso
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function generateToken()
|
||||
{
|
||||
return sha1(uniqid('sysPass-API', true) . time());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener el token de la API de un usuario
|
||||
*
|
||||
* @return bool
|
||||
* @throws SPException
|
||||
*/
|
||||
private function getUserToken()
|
||||
{
|
||||
$query = /** @lang SQL */
|
||||
'SELECT authtoken_token FROM authTokens WHERE authtoken_userId = :userid LIMIT 1';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($this->userId, 'userid');
|
||||
|
||||
try {
|
||||
$queryRes = DB::getResults($Data);
|
||||
} catch (SPException $e) {
|
||||
throw new SPException(SPException::SP_CRITICAL, __('Error interno', false));
|
||||
}
|
||||
|
||||
if ($Data->getQueryNumRows() === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->token = $queryRes->authtoken_token;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actualizar un token
|
||||
*
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function updateToken()
|
||||
{
|
||||
$this->checkTokenExist();
|
||||
|
||||
if ($this->refreshToken) {
|
||||
$this->refreshToken();
|
||||
}
|
||||
|
||||
$query = /** @lang SQL */
|
||||
'UPDATE authTokens
|
||||
SET authtoken_userId = :userid,
|
||||
authtoken_actionId = :actionid,
|
||||
authtoken_createdBy = :createdby,
|
||||
authtoken_token = :token,
|
||||
authtoken_startDate = UNIX_TIMESTAMP()
|
||||
WHERE authtoken_id = :id LIMIT 1';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($this->tokenId, 'id');
|
||||
$Data->addParam($this->userId, 'userid');
|
||||
$Data->addParam($this->actionId, 'actionid');
|
||||
$Data->addParam(Session::getUserData()->getUserId(), 'createdby');
|
||||
$Data->addParam($this->getUserToken() ? $this->token : $this->generateToken(), 'token');
|
||||
$Data->setOnErrorMessage(__('Error interno', false));
|
||||
|
||||
DB::getQuery($Data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Eliminar token
|
||||
*
|
||||
* @param $id
|
||||
*/
|
||||
public function deleteToken($id)
|
||||
{
|
||||
$query = /** @lang SQL */
|
||||
'DELETE FROM authTokens WHERE authtoken_id = ? LIMIT 1';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($id);
|
||||
$Data->setOnErrorMessage(__('Error interno', false));
|
||||
|
||||
DB::getQuery($Data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Eliminar token
|
||||
*
|
||||
* @param array $ids
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
*/
|
||||
public function deleteTokenBatch(array $ids)
|
||||
{
|
||||
$query = /** @lang SQL */
|
||||
'DELETE FROM authTokens WHERE authtoken_id IN (' . implode(',', array_fill(0, count($ids), '?')) . ')';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->setParams($ids);
|
||||
$Data->setOnErrorMessage(__('Error interno', false));
|
||||
|
||||
DB::getQuery($Data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getUserId()
|
||||
{
|
||||
return $this->userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $userId
|
||||
*/
|
||||
public function setUserId($userId)
|
||||
{
|
||||
$this->userId = $userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getTokenId()
|
||||
{
|
||||
return $this->tokenId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $tokenId
|
||||
*/
|
||||
public function setTokenId($tokenId)
|
||||
{
|
||||
$this->tokenId = $tokenId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getActionId()
|
||||
{
|
||||
return $this->actionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $actionId
|
||||
*/
|
||||
public function setActionId($actionId)
|
||||
{
|
||||
$this->actionId = $actionId;
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
/**
|
||||
* sysPass
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link http://syspass.org
|
||||
* @author nuxsmin
|
||||
* @link http://syspass.org
|
||||
* @copyright 2012-2017, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
@@ -26,10 +26,6 @@ namespace SP\Api;
|
||||
|
||||
use SP\Core\Acl;
|
||||
use SP\Core\ActionsInterface;
|
||||
use SP\Core\Exceptions\SPException;
|
||||
use SP\DataModel\ItemSearchData;
|
||||
use SP\Storage\DB;
|
||||
use SP\Storage\QueryData;
|
||||
|
||||
defined('APP_ROOT') || die();
|
||||
|
||||
@@ -40,92 +36,6 @@ defined('APP_ROOT') || die();
|
||||
*/
|
||||
class ApiTokensUtil
|
||||
{
|
||||
/**
|
||||
* Obtener los tokens de la API
|
||||
*
|
||||
* @param int $tokenId opcional, con el Id del token a consultar
|
||||
* @param bool $returnRawData Devolver la consulta tal cual
|
||||
* @return array|object con la lista de tokens
|
||||
*/
|
||||
public static function getTokens($tokenId = null, $returnRawData = false)
|
||||
{
|
||||
$query = 'SELECT authtoken_id,' .
|
||||
'authtoken_userId,' .
|
||||
'authtoken_actionId, ' .
|
||||
'authtoken_token, ' .
|
||||
'user_login ' .
|
||||
'FROM authTokens ' .
|
||||
'LEFT JOIN usrData ON user_id = authtoken_userId ';
|
||||
|
||||
$Data = new QueryData();
|
||||
|
||||
if (null !== $tokenId) {
|
||||
$query .= 'WHERE authtoken_id = ? LIMIT 1';
|
||||
$Data->addParam($tokenId);
|
||||
} else {
|
||||
$query .= 'ORDER BY user_login';
|
||||
}
|
||||
|
||||
$Data->setQuery($query);
|
||||
|
||||
if (!$returnRawData) {
|
||||
$queryRes = DB::getResultsArray($Data);
|
||||
|
||||
foreach ($queryRes as &$token) {
|
||||
$token->authtoken_actionId = Acl::getActionName($token->authtoken_actionId);
|
||||
}
|
||||
} else {
|
||||
$queryRes = DB::getResults($Data);
|
||||
}
|
||||
|
||||
return $queryRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener los tokens de la API de una búsqueda
|
||||
* @param ItemSearchData $SearchData
|
||||
* @return array|object con la lista de tokens
|
||||
*/
|
||||
public static function getTokensMgmtSearch(ItemSearchData $SearchData)
|
||||
{
|
||||
$query = 'SELECT authtoken_id,' .
|
||||
'authtoken_userId,' .
|
||||
'authtoken_actionId, ' .
|
||||
'authtoken_token, ' .
|
||||
'user_login ' .
|
||||
'FROM authTokens ' .
|
||||
'LEFT JOIN usrData ON user_id = authtoken_userId ';
|
||||
|
||||
$Data = new QueryData();
|
||||
|
||||
if ($SearchData->getSeachString() !== '') {
|
||||
$search = '%' . $SearchData->getSeachString() . '%';
|
||||
$query .= ' WHERE user_login LIKE ?';
|
||||
|
||||
$Data->addParam($search);
|
||||
}
|
||||
|
||||
$query .= ' ORDER BY user_login';
|
||||
$query .= ' LIMIT ?, ?';
|
||||
|
||||
$Data->addParam($SearchData->getLimitStart());
|
||||
$Data->addParam($SearchData->getLimitCount());
|
||||
|
||||
$Data->setQuery($query);
|
||||
|
||||
DB::setFullRowCount();
|
||||
|
||||
$queryRes = DB::getResultsArray($Data);
|
||||
|
||||
foreach ($queryRes as &$token) {
|
||||
$token->authtoken_actionId = Acl::getActionName($token->authtoken_actionId);
|
||||
}
|
||||
|
||||
$queryRes['count'] = $Data->getQueryNumRows();
|
||||
|
||||
return $queryRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Devuelver un array de acciones posibles para los tokens
|
||||
*
|
||||
@@ -146,32 +56,4 @@ class ApiTokensUtil
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener el usuario a partir del token
|
||||
*
|
||||
* @param $token string El token de autorización
|
||||
* @return bool|mixed
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public static function getUserIdForToken($token)
|
||||
{
|
||||
$query = 'SELECT authtoken_userId FROM authTokens WHERE authtoken_token = ? LIMIT 1';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($token);
|
||||
|
||||
try {
|
||||
$queryRes = DB::getResults($Data);
|
||||
} catch (SPException $e) {
|
||||
throw new SPException(SPException::SP_CRITICAL, __('Error interno', false));
|
||||
}
|
||||
|
||||
if ($Data->getQueryNumRows() === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $queryRes->authtoken_userId;
|
||||
}
|
||||
}
|
||||
@@ -88,11 +88,12 @@ class SyspassApi extends ApiBase
|
||||
$LogMessage->addDetails(__('Origen', false), 'API');
|
||||
$this->Log->writeLog();
|
||||
|
||||
$securedKey = Crypt::unlockSecuredKey($AccountData->getAccountKey(), $this->mPass);
|
||||
$mPass = $this->getMPass();
|
||||
$securedKey = Crypt::unlockSecuredKey($AccountData->getAccountKey(), $mPass);
|
||||
|
||||
$ret = [
|
||||
'itemId' => $accountId,
|
||||
'pass' => Crypt::decrypt($AccountData->getAccountPass(), $securedKey)
|
||||
'pass' => Crypt::decrypt($AccountData->getAccountPass(), $securedKey, $mPass)
|
||||
];
|
||||
|
||||
if ($this->getParam('details', false, 0)) {
|
||||
@@ -158,6 +159,11 @@ class SyspassApi extends ApiBase
|
||||
* Añadir una nueva cuenta
|
||||
*
|
||||
* @return string La cadena en formato JSON
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
|
||||
* @throws \Defuse\Crypto\Exception\CryptoException
|
||||
* @throws \Defuse\Crypto\Exception\BadFormatException
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function addAccount()
|
||||
|
||||
@@ -31,8 +31,6 @@ use SP\DataModel\UserPassRecoverData;
|
||||
use SP\Html\Html;
|
||||
use SP\Log\Email;
|
||||
use SP\Mgmt\Users\UserPassRecover;
|
||||
use SP\Storage\DB;
|
||||
use SP\Storage\QueryData;
|
||||
use SP\Util\Util;
|
||||
|
||||
/**
|
||||
@@ -79,32 +77,6 @@ class AuthUtil
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comprobar el token de seguridad
|
||||
*
|
||||
* @param $actionId int El id de la accion
|
||||
* @param $token string El token de seguridad
|
||||
* @return bool
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public static function checkAuthToken($actionId, $token)
|
||||
{
|
||||
$query = /** @lang SQL */
|
||||
'SELECT authtoken_id
|
||||
FROM authTokens
|
||||
WHERE authtoken_actionId = ?
|
||||
AND authtoken_token = ? LIMIT 1';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($actionId);
|
||||
$Data->addParam($token);
|
||||
|
||||
DB::getQuery($Data);
|
||||
|
||||
return $Data->getQueryNumRows() === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Devuelve el typo de autentificación del servidor web
|
||||
*
|
||||
|
||||
@@ -29,7 +29,6 @@ use SP\Account\AccountFavorites;
|
||||
use SP\Account\AccountHistory;
|
||||
use SP\Account\AccountHistoryUtil;
|
||||
use SP\Account\AccountUtil;
|
||||
use SP\Api\ApiTokens;
|
||||
use SP\Auth\AuthUtil;
|
||||
use SP\Core\ActionsInterface;
|
||||
use SP\Core\Messages\LogMessage;
|
||||
@@ -51,6 +50,7 @@ use SP\Forms\UserForm;
|
||||
use SP\Http\Request;
|
||||
use SP\Log\Email;
|
||||
use SP\Log\Log;
|
||||
use SP\Mgmt\ApiTokens\ApiToken;
|
||||
use SP\Mgmt\Categories\Category;
|
||||
use SP\Mgmt\Customers\Customer;
|
||||
use SP\Mgmt\CustomFields\CustomField;
|
||||
@@ -593,37 +593,48 @@ class ItemActionController implements ItemControllerInterface
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
* @throws \phpmailer\phpmailerException
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
*/
|
||||
protected function tokenAction()
|
||||
{
|
||||
$Form = new ApiTokenForm($this->itemId);
|
||||
|
||||
$refresh = Request::analyze('refreshtoken', false, false, true);
|
||||
|
||||
switch ($this->actionId) {
|
||||
case ActionsInterface::ACTION_MGM_APITOKENS_NEW:
|
||||
$Form->validate($this->actionId);
|
||||
$Form->getItemData()->addToken();
|
||||
|
||||
if ($refresh === true) {
|
||||
ApiToken::getItem($Form->getItemData())->refreshToken()->add();
|
||||
} else {
|
||||
ApiToken::getItem($Form->getItemData())->add();
|
||||
}
|
||||
|
||||
$this->LogMessage->setAction(__('Crear Autorización', false));
|
||||
$this->LogMessage->addDescription(__('Autorización creada', false));
|
||||
$this->LogMessage->addDetails(__('Usuario', false), UserUtil::getUserLoginById($Form->getItemData()->getUserId()));
|
||||
$this->LogMessage->addDetails(__('Usuario', false), UserUtil::getUserLoginById($Form->getItemData()->getAuthtokenUserId()));
|
||||
break;
|
||||
case ActionsInterface::ACTION_MGM_APITOKENS_EDIT:
|
||||
$Form->validate($this->actionId);
|
||||
$Form->getItemData()->updateToken();
|
||||
|
||||
if ($refresh === true) {
|
||||
ApiToken::getItem($Form->getItemData())->refreshToken()->update();
|
||||
} else {
|
||||
ApiToken::getItem($Form->getItemData())->update();
|
||||
}
|
||||
|
||||
$this->LogMessage->setAction(__('Actualizar Autorización', false));
|
||||
$this->LogMessage->addDescription(__('Autorización actualizada', false));
|
||||
$this->LogMessage->addDetails(__('Usuario', false), UserUtil::getUserLoginById($Form->getItemData()->getUserId()));
|
||||
$this->LogMessage->addDetails(__('Usuario', false), UserUtil::getUserLoginById($Form->getItemData()->getAuthtokenUserId()));
|
||||
break;
|
||||
case ActionsInterface::ACTION_MGM_APITOKENS_DELETE:
|
||||
$ApiToken = new ApiTokens();
|
||||
|
||||
if (is_array($this->itemId)) {
|
||||
$ApiToken->deleteTokenBatch($this->itemId);
|
||||
ApiToken::getItem()->deleteBatch($this->itemId);
|
||||
|
||||
$this->LogMessage->addDescription(__('Autorizaciones eliminadas', false));
|
||||
} else {
|
||||
$ApiToken->deleteToken($this->itemId);
|
||||
ApiToken::getItem()->delete($this->itemId);
|
||||
|
||||
$this->LogMessage->addDescription(__('Autorización eliminada', false));
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ use SP\Core\Exceptions\SPException;
|
||||
use SP\Core\Template;
|
||||
use SP\DataModel\ItemSearchData;
|
||||
use SP\Http\Request;
|
||||
use SP\Mgmt\ApiTokens\ApiToken;
|
||||
use SP\Mgmt\ApiTokens\ApiTokenSearch;
|
||||
use SP\Mgmt\Categories\CategorySearch;
|
||||
use SP\Mgmt\Customers\CustomerSearch;
|
||||
use SP\Mgmt\CustomFields\CustomFieldDefSearch;
|
||||
@@ -377,7 +379,7 @@ class ItemListController extends GridTabControllerBase implements ActionsInterfa
|
||||
}
|
||||
|
||||
$Grid = $this->getGrids()->getTokensGrid();
|
||||
$Grid->getData()->setData(ApiTokensUtil::getTokensMgmtSearch($this->ItemSearchData));
|
||||
$Grid->getData()->setData(ApiTokenSearch::getItem()->getMgmtSearch($this->ItemSearchData));
|
||||
$Grid->updatePager();
|
||||
|
||||
$this->view->append('tabs', $Grid);
|
||||
|
||||
@@ -36,6 +36,7 @@ use SP\Core\SessionUtil;
|
||||
use SP\Core\Template;
|
||||
use SP\DataModel\ItemSearchData;
|
||||
use SP\Http\Request;
|
||||
use SP\Mgmt\ApiTokens\ApiTokenSearch;
|
||||
use SP\Mgmt\Categories\CategorySearch;
|
||||
use SP\Mgmt\Customers\CustomerSearch;
|
||||
use SP\Mgmt\CustomFields\CustomFieldDefSearch;
|
||||
@@ -248,6 +249,7 @@ class ItemSearchController extends GridItemsSearchController implements ActionsI
|
||||
* Obtener los tokens API de una búsqueda
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \SP\Core\Exceptions\InvalidArgumentException
|
||||
*/
|
||||
public function getTokens()
|
||||
{
|
||||
@@ -260,7 +262,7 @@ class ItemSearchController extends GridItemsSearchController implements ActionsI
|
||||
$this->view->addTemplate('datagrid-table', 'grid');
|
||||
|
||||
$Grid = $this->getGrids()->getTokensGrid();
|
||||
$Grid->getData()->setData(ApiTokensUtil::getTokensMgmtSearch($this->ItemSearchData));
|
||||
$Grid->getData()->setData(ApiTokenSearch::getItem()->getMgmtSearch($this->ItemSearchData));
|
||||
$Grid->updatePager();
|
||||
|
||||
$this->updatePager($Grid->getPager(), $this->ItemSearchData);
|
||||
|
||||
@@ -39,6 +39,7 @@ use SP\Core\Session;
|
||||
use SP\Core\SessionUtil;
|
||||
use SP\Core\Template;
|
||||
use SP\DataModel\AccountExtData;
|
||||
use SP\DataModel\ApiTokenData;
|
||||
use SP\DataModel\CategoryData;
|
||||
use SP\DataModel\CustomerData;
|
||||
use SP\DataModel\CustomFieldData;
|
||||
@@ -51,6 +52,7 @@ use SP\DataModel\UserPassData;
|
||||
use SP\Http\Request;
|
||||
use SP\Log\Email;
|
||||
use SP\Log\Log;
|
||||
use SP\Mgmt\ApiTokens\ApiToken;
|
||||
use SP\Mgmt\Categories\Category;
|
||||
use SP\Mgmt\Customers\Customer;
|
||||
use SP\Mgmt\CustomFields\CustomField;
|
||||
@@ -66,6 +68,7 @@ use SP\Mgmt\PublicLinks\PublicLink;
|
||||
use SP\Mgmt\Tags\Tag;
|
||||
use SP\Mgmt\Users\User;
|
||||
use SP\Mgmt\Users\UserPass;
|
||||
use SP\Mgmt\Users\UserUtil;
|
||||
use SP\Util\Checks;
|
||||
use SP\Util\ImageUtil;
|
||||
use SP\Util\Json;
|
||||
@@ -392,18 +395,19 @@ class ItemShowController extends ControllerBase implements ActionsInterface, Ite
|
||||
$this->module = self::ACTION_MGM_APITOKENS;
|
||||
$this->view->addTemplate('tokens');
|
||||
|
||||
$token = ApiTokensUtil::getTokens($this->itemId, true);
|
||||
$ApiTokenData = $this->itemId ? ApiToken::getItem()->getById($this->itemId) : new ApiTokenData();
|
||||
|
||||
$this->view->assign('users', User::getItem()->getItemsForSelect());
|
||||
$this->view->assign('actions', ApiTokensUtil::getTokenActions());
|
||||
$this->view->assign('token', $token);
|
||||
$this->view->assign('gotData', is_object($token));
|
||||
$this->view->assign('ApiTokenData', $ApiTokenData);
|
||||
$this->view->assign('isDisabled', ($this->view->actionId === self::ACTION_MGM_APITOKENS_VIEW) ? 'disabled' : '');
|
||||
$this->view->assign('isReadonly', $this->view->isDisabled ? 'readonly' : '');
|
||||
|
||||
if ($this->view->isView === true) {
|
||||
$Log = Log::newLog(__('Autorizaciones', false));
|
||||
$LogMessage = $Log->getLogMessage();
|
||||
$LogMessage->addDescription(__('Token de autorización visualizado'));
|
||||
$LogMessage->addDetails(__('Usuario'), $token->user_login);
|
||||
$LogMessage->addDetails(__('Usuario'), UserUtil::getUserLoginById($ApiTokenData->authtoken_userId));
|
||||
$Log->writeLog();
|
||||
|
||||
Email::sendEmail($LogMessage);
|
||||
|
||||
230
inc/SP/DataModel/ApiTokenData.class.php
Normal file
230
inc/SP/DataModel/ApiTokenData.class.php
Normal file
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
/**
|
||||
* sysPass
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link http://syspass.org
|
||||
* @copyright 2012-2017, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
* sysPass is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sysPass is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace SP\DataModel;
|
||||
|
||||
/**
|
||||
* Class ApiTokenData
|
||||
*
|
||||
* @package SP\DataModel
|
||||
*/
|
||||
class ApiTokenData extends DataModelBase implements DataModelInterface
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $authtoken_id;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $authtoken_key;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $authtoken_pass;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $authtoken_userId;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $authtoken_token = '';
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $authtoken_createdBy;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $authtoken_startDate;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $authtoken_actionId;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $authtoken_hash;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getAuthtokenId()
|
||||
{
|
||||
return (int)$this->authtoken_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $authtoken_id
|
||||
*/
|
||||
public function setAuthtokenId($authtoken_id)
|
||||
{
|
||||
$this->authtoken_id = (int)$authtoken_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAuthtokenKey()
|
||||
{
|
||||
return $this->authtoken_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $authtoken_key
|
||||
*/
|
||||
public function setAuthtokenKey($authtoken_key)
|
||||
{
|
||||
$this->authtoken_key = $authtoken_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getAuthtokenUserId()
|
||||
{
|
||||
return (int)$this->authtoken_userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $authtoken_userId
|
||||
*/
|
||||
public function setAuthtokenUserId($authtoken_userId)
|
||||
{
|
||||
$this->authtoken_userId = (int)$authtoken_userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAuthtokenToken()
|
||||
{
|
||||
return $this->authtoken_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $authtoken_token
|
||||
*/
|
||||
public function setAuthtokenToken($authtoken_token)
|
||||
{
|
||||
$this->authtoken_token = $authtoken_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getAuthtokenCreatedBy()
|
||||
{
|
||||
return (int)$this->authtoken_createdBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $authtoken_createdBy
|
||||
*/
|
||||
public function setAuthtokenCreatedBy($authtoken_createdBy)
|
||||
{
|
||||
$this->authtoken_createdBy = (int)$authtoken_createdBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getAuthtokenStartDate()
|
||||
{
|
||||
return (int)$this->authtoken_startDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $authtoken_startDate
|
||||
*/
|
||||
public function setAuthtokenStartDate($authtoken_startDate)
|
||||
{
|
||||
$this->authtoken_startDate = (int)$authtoken_startDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return (int)$this->authtoken_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getAuthtokenActionId()
|
||||
{
|
||||
return (int)$this->authtoken_actionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $authtoken_actionId
|
||||
*/
|
||||
public function setAuthtokenActionId($authtoken_actionId)
|
||||
{
|
||||
$this->authtoken_actionId = (int)$authtoken_actionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAuthtokenHash()
|
||||
{
|
||||
return $this->authtoken_hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $authtoken_hash
|
||||
*/
|
||||
public function setAuthtokenHash($authtoken_hash)
|
||||
{
|
||||
$this->authtoken_hash = $authtoken_hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAuthtokenPass()
|
||||
{
|
||||
return $this->authtoken_pass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $authtoken_pass
|
||||
*/
|
||||
public function setAuthtokenPass($authtoken_pass)
|
||||
{
|
||||
$this->authtoken_pass = $authtoken_pass;
|
||||
}
|
||||
}
|
||||
@@ -24,9 +24,9 @@
|
||||
|
||||
namespace SP\Forms;
|
||||
|
||||
use SP\Api\ApiTokens;
|
||||
use SP\Core\ActionsInterface;
|
||||
use SP\Core\Exceptions\ValidationException;
|
||||
use SP\DataModel\ApiTokenData;
|
||||
use SP\Http\Request;
|
||||
|
||||
/**
|
||||
@@ -37,15 +37,15 @@ use SP\Http\Request;
|
||||
class ApiTokenForm extends FormBase implements FormInterface
|
||||
{
|
||||
/**
|
||||
* @var ApiTokens
|
||||
* @var ApiTokenData
|
||||
*/
|
||||
protected $ApiTokens;
|
||||
protected $ApiTokenData;
|
||||
|
||||
/**
|
||||
* Validar el formulario
|
||||
*
|
||||
* @param $action
|
||||
* @return bool
|
||||
* @return ApiTokenForm
|
||||
* @throws \SP\Core\Exceptions\ValidationException
|
||||
*/
|
||||
public function validate($action)
|
||||
@@ -58,7 +58,7 @@ class ApiTokenForm extends FormBase implements FormInterface
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,11 +68,11 @@ class ApiTokenForm extends FormBase implements FormInterface
|
||||
*/
|
||||
protected function analyzeRequestData()
|
||||
{
|
||||
$this->ApiTokens = new ApiTokens();
|
||||
$this->ApiTokens->setTokenId($this->itemId);
|
||||
$this->ApiTokens->setUserId(Request::analyze('users', 0));
|
||||
$this->ApiTokens->setActionId(Request::analyze('actions', 0));
|
||||
$this->ApiTokens->setRefreshToken(Request::analyze('refreshtoken', false, false, true));
|
||||
$this->ApiTokenData = new ApiTokenData();
|
||||
$this->ApiTokenData->setAuthtokenId($this->itemId);
|
||||
$this->ApiTokenData->setAuthtokenUserId(Request::analyze('users', 0));
|
||||
$this->ApiTokenData->setAuthtokenActionId(Request::analyze('actions', 0));
|
||||
$this->ApiTokenData->setAuthtokenHash(Request::analyzeEncrypted('pass'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,18 +80,20 @@ class ApiTokenForm extends FormBase implements FormInterface
|
||||
*/
|
||||
protected function checkCommon()
|
||||
{
|
||||
if ($this->ApiTokens->getUserId() === 0) {
|
||||
if ($this->ApiTokenData->getAuthtokenUserId() === 0) {
|
||||
throw new ValidationException(__('Usuario no indicado', false));
|
||||
} elseif ($this->ApiTokens->getActionId() === 0) {
|
||||
} elseif ($this->ApiTokenData->getAuthtokenActionId() === 0) {
|
||||
throw new ValidationException(__('Acción no indicada', false));
|
||||
} elseif ($this->ApiTokenData->getAuthtokenKey() === '') {
|
||||
throw new ValidationException(__('La clave no puede estar en blanco', false));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ApiTokens
|
||||
* @return ApiTokenData
|
||||
*/
|
||||
public function getItemData()
|
||||
{
|
||||
return $this->ApiTokens;
|
||||
return $this->ApiTokenData;
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ interface FormInterface
|
||||
* Validar el formulario
|
||||
*
|
||||
* @param $action
|
||||
* @return bool
|
||||
* @return FormInterface
|
||||
* @throws \SP\Core\Exceptions\ValidationException
|
||||
*/
|
||||
public function validate($action);
|
||||
|
||||
409
inc/SP/Mgmt/ApiTokens/ApiToken.class.php
Normal file
409
inc/SP/Mgmt/ApiTokens/ApiToken.class.php
Normal file
@@ -0,0 +1,409 @@
|
||||
<?php
|
||||
/**
|
||||
* sysPass
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link http://syspass.org
|
||||
* @copyright 2012-2017, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
* sysPass is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sysPass is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace SP\Mgmt\ApiTokens;
|
||||
|
||||
use SP\Core\Crypt\Crypt;
|
||||
use SP\Core\Crypt\Hash;
|
||||
use SP\Core\Crypt\Session as CryptSession;
|
||||
use SP\Core\Exceptions\SPException;
|
||||
use SP\Core\Session;
|
||||
use SP\DataModel\ApiTokenData;
|
||||
use SP\Mgmt\ItemInterface;
|
||||
use SP\Mgmt\ItemTrait;
|
||||
use SP\Storage\DB;
|
||||
use SP\Storage\QueryData;
|
||||
use SP\Util\Util;
|
||||
|
||||
/**
|
||||
* Class ApiToken
|
||||
*
|
||||
* @package SP\Mgmt\ApiTokens
|
||||
*/
|
||||
class ApiToken extends ApiTokenBase implements ItemInterface
|
||||
{
|
||||
use ItemTrait;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws \Defuse\Crypto\Exception\CryptoException
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
*/
|
||||
public function add()
|
||||
{
|
||||
if ($this->checkDuplicatedOnAdd()) {
|
||||
throw new SPException(SPException::SP_WARNING, __('La autorización ya existe', false));
|
||||
}
|
||||
|
||||
$token = $this->getTokenByUserId($this->itemData->getAuthtokenUserId());
|
||||
$this->setSecureData($token);
|
||||
|
||||
$query = /** @lang SQL */
|
||||
'INSERT INTO authTokens
|
||||
SET authtoken_userId = ?,
|
||||
authtoken_actionId = ?,
|
||||
authtoken_createdBy = ?,
|
||||
authtoken_token = ?,
|
||||
authtoken_key = ?,
|
||||
authtoken_pass = ?,
|
||||
authtoken_hash = ?,
|
||||
authtoken_startDate = UNIX_TIMESTAMP()';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($this->itemData->getAuthtokenUserId());
|
||||
$Data->addParam($this->itemData->getAuthtokenActionId());
|
||||
$Data->addParam(Session::getUserData()->getUserId());
|
||||
$Data->addParam($token);
|
||||
$Data->addParam($this->itemData->getAuthtokenKey());
|
||||
$Data->addParam($this->itemData->getAuthtokenPass());
|
||||
$Data->addParam(Hash::hashKey($this->itemData->getAuthtokenHash()));
|
||||
$Data->setOnErrorMessage(__('Error interno', false));
|
||||
|
||||
DB::getQuery($Data);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws SPException
|
||||
*/
|
||||
public function checkDuplicatedOnAdd()
|
||||
{
|
||||
$query = /** @lang SQL */
|
||||
'SELECT authtoken_id FROM authTokens
|
||||
WHERE authtoken_userId = ?
|
||||
AND authtoken_actionId = ? LIMIT 1';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($this->itemData->getAuthtokenUserId());
|
||||
$Data->addParam($this->itemData->getAuthtokenActionId());
|
||||
|
||||
DB::getResults($Data);
|
||||
|
||||
return $Data->getQueryNumRows() === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener el token de la API de un usuario
|
||||
*
|
||||
* @param $id
|
||||
* @return bool
|
||||
*/
|
||||
private function getTokenByUserId($id)
|
||||
{
|
||||
$query = /** @lang SQL */
|
||||
'SELECT authtoken_token FROM authTokens WHERE authtoken_userId = ? LIMIT 1';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($id);
|
||||
|
||||
$queryRes = DB::getResults($Data);
|
||||
|
||||
return $Data->getQueryNumRows() === 1 ? $queryRes->authtoken_token : $this->generateToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generar un token de acceso
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function generateToken()
|
||||
{
|
||||
return Util::generateRandomBytes(32);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id int
|
||||
* @return $this
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
$query = /** @lang SQL */
|
||||
'DELETE FROM authTokens WHERE authtoken_id = ? LIMIT 1';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($id);
|
||||
$Data->setOnErrorMessage(__('Error interno', false));
|
||||
|
||||
DB::getQuery($Data);
|
||||
|
||||
if ($Data->getQueryNumRows() === 0) {
|
||||
throw new SPException(SPException::SP_INFO, __('Token no encontrado', false));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \Defuse\Crypto\Exception\CryptoException
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function update()
|
||||
{
|
||||
if ($this->checkDuplicatedOnUpdate()) {
|
||||
throw new SPException(SPException::SP_WARNING, __('La autorización ya existe', false));
|
||||
}
|
||||
|
||||
$token = $this->getTokenByUserId($this->itemData->getAuthtokenUserId());
|
||||
$this->setSecureData($token);
|
||||
|
||||
$query = /** @lang SQL */
|
||||
'UPDATE authTokens
|
||||
SET authtoken_userId = ?,
|
||||
authtoken_actionId = ?,
|
||||
authtoken_createdBy = ?,
|
||||
authtoken_token = ?,
|
||||
authtoken_key = ?,
|
||||
authtoken_pass = ?,
|
||||
authtoken_hash = ?,
|
||||
authtoken_startDate = UNIX_TIMESTAMP()
|
||||
WHERE authtoken_id = ? LIMIT 1';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($this->itemData->getAuthtokenUserId());
|
||||
$Data->addParam($this->itemData->getAuthtokenActionId());
|
||||
$Data->addParam(Session::getUserData()->getUserId());
|
||||
$Data->addParam($token);
|
||||
$Data->addParam($this->itemData->getAuthtokenKey());
|
||||
$Data->addParam($this->itemData->getAuthtokenPass());
|
||||
$Data->addParam(Hash::hashKey($this->itemData->getAuthtokenHash()));
|
||||
$Data->addParam($this->itemData->getAuthtokenId());
|
||||
$Data->setOnErrorMessage(__('Error interno', false));
|
||||
|
||||
DB::getQuery($Data);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function checkDuplicatedOnUpdate()
|
||||
{
|
||||
$query = /** @lang SQL */
|
||||
'SELECT authtoken_id FROM authTokens
|
||||
WHERE authtoken_userId = ?
|
||||
AND authtoken_actionId = ?
|
||||
AND authtoken_id <> ? LIMIT 1';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($this->itemData->getAuthtokenUserId());
|
||||
$Data->addParam($this->itemData->getAuthtokenActionId());
|
||||
$Data->addParam($this->itemData->getAuthtokenId());
|
||||
|
||||
DB::getResults($Data);
|
||||
|
||||
return $Data->getQueryNumRows() === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerar el hash de los tokens de un usuario
|
||||
*
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \Defuse\Crypto\Exception\CryptoException
|
||||
*/
|
||||
public function refreshToken()
|
||||
{
|
||||
$token = $this->generateToken();
|
||||
$this->setSecureData($token);
|
||||
|
||||
$query = /** @lang SQL */
|
||||
'UPDATE authTokens
|
||||
SET authtoken_token = ?,
|
||||
authtoken_hash = ?,
|
||||
authtoken_key = ?,
|
||||
authtoken_pass = ?,
|
||||
authtoken_startDate = UNIX_TIMESTAMP()
|
||||
WHERE authtoken_userId = ? LIMIT 1';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($this->generateToken());
|
||||
$Data->addParam(Hash::hashKey($this->itemData->getAuthtokenHash()));
|
||||
$Data->addParam($this->itemData->getAuthtokenKey());
|
||||
$Data->addParam($this->itemData->getAuthtokenPass());
|
||||
$Data->addParam($this->itemData->getAuthtokenUserId());
|
||||
$Data->setOnErrorMessage(__('Error interno', false));
|
||||
|
||||
DB::getQuery($Data);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generar la llave segura del token
|
||||
*
|
||||
* @param $token
|
||||
* @throws \Defuse\Crypto\Exception\CryptoException
|
||||
*/
|
||||
private function setSecureData($token)
|
||||
{
|
||||
$key = $this->itemData->getAuthtokenHash() . $token;
|
||||
$securedKey = Crypt::makeSecuredKey($key);
|
||||
|
||||
$this->itemData->setAuthtokenKey($securedKey);
|
||||
$this->itemData->setAuthtokenPass(Crypt::encrypt(CryptSession::getSessionKey(), $securedKey, $key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id int
|
||||
* @return ApiTokenData
|
||||
*/
|
||||
public function getById($id)
|
||||
{
|
||||
$query = /** @lang SQL */
|
||||
'SELECT authtoken_id,
|
||||
authtoken_userId,
|
||||
authtoken_actionId,
|
||||
authtoken_createdBy,
|
||||
authtoken_startDate,
|
||||
authtoken_token
|
||||
FROM authTokens
|
||||
WHERE authtoken_id = ? LIMIT 1';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setMapClassName($this->getDataModel());
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($id);
|
||||
|
||||
return DB::getResults($Data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
// TODO: Implement getAll() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id int
|
||||
* @return mixed
|
||||
*/
|
||||
public function checkInUse($id)
|
||||
{
|
||||
// TODO: Implement checkInUse() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Eliminar elementos en lote
|
||||
*
|
||||
* @param array $ids
|
||||
* @return $this
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
*/
|
||||
public function deleteBatch(array $ids)
|
||||
{
|
||||
$query = /** @lang SQL */
|
||||
'DELETE FROM authTokens WHERE authtoken_id IN (' . $this->getParamsFromArray($ids) . ')';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->setParams($ids);
|
||||
$Data->setOnErrorMessage(__('Error interno', false));
|
||||
|
||||
DB::getQuery($Data);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Devolver los elementos con los ids especificados
|
||||
*
|
||||
* @param array $ids
|
||||
* @return mixed
|
||||
*/
|
||||
public function getByIdBatch(array $ids)
|
||||
{
|
||||
// TODO: Implement getByIdBatch() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener el usuario a partir del token
|
||||
*
|
||||
* @param $token string El token de autorización
|
||||
* @return bool|mixed
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function getUserIdForToken($token)
|
||||
{
|
||||
$query = /** @lang SQL */
|
||||
'SELECT authtoken_userId FROM authTokens WHERE authtoken_token = ? LIMIT 1';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($token);
|
||||
|
||||
$queryRes = DB::getResults($Data);
|
||||
|
||||
return $Data->getQueryNumRows() === 1 ? $queryRes->authtoken_userId : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Devolver los datos de un token
|
||||
*
|
||||
* @param $actionId int El id de la accion
|
||||
* @param $token string El token de seguridad
|
||||
* @return false|ApiTokenData
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function getTokenByToken($actionId, $token)
|
||||
{
|
||||
$query = /** @lang SQL */
|
||||
'SELECT authtoken_userId,
|
||||
authtoken_key,
|
||||
authtoken_pass,
|
||||
authtoken_hash
|
||||
FROM authTokens
|
||||
WHERE authtoken_actionId = ?
|
||||
AND authtoken_token = ? LIMIT 1';
|
||||
|
||||
$Data = new QueryData();
|
||||
$Data->setMapClassName($this->getDataModel());
|
||||
$Data->setQuery($query);
|
||||
$Data->addParam($actionId);
|
||||
$Data->addParam($token);
|
||||
|
||||
$queryRes = DB::getResults($Data);
|
||||
|
||||
return $Data->getQueryNumRows() === 1 ? $queryRes : false;
|
||||
}
|
||||
}
|
||||
66
inc/SP/Mgmt/ApiTokens/ApiTokenBase.class.php
Normal file
66
inc/SP/Mgmt/ApiTokens/ApiTokenBase.class.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/**
|
||||
* sysPass
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link http://syspass.org
|
||||
* @copyright 2012-2017, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
* sysPass is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sysPass is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace SP\Mgmt\ApiTokens;
|
||||
|
||||
defined('APP_ROOT') || die();
|
||||
|
||||
use SP\DataModel\ApiTokenData;
|
||||
use SP\Mgmt\ItemBase;
|
||||
|
||||
/**
|
||||
* Class ApiTokensBase
|
||||
*
|
||||
* @package SP\Mgmt\ApiTokens
|
||||
*/
|
||||
abstract class ApiTokenBase extends ItemBase
|
||||
{
|
||||
/** @var ApiTokenData */
|
||||
protected $itemData;
|
||||
|
||||
/**
|
||||
* ApiTokensBase constructor.
|
||||
*
|
||||
* @param $itemData
|
||||
* @throws \SP\Core\Exceptions\InvalidClassException
|
||||
*/
|
||||
public function __construct($itemData = null)
|
||||
{
|
||||
if (!$this->dataModel) {
|
||||
$this->setDataModel(ApiTokenData::class);
|
||||
}
|
||||
|
||||
parent::__construct($itemData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Devolver los datos del elemento
|
||||
*
|
||||
* @return ApiTokenData
|
||||
*/
|
||||
public function getItemData()
|
||||
{
|
||||
return parent::getItemData();
|
||||
}
|
||||
}
|
||||
83
inc/SP/Mgmt/ApiTokens/ApiTokenSearch.class.php
Normal file
83
inc/SP/Mgmt/ApiTokens/ApiTokenSearch.class.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* sysPass
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link http://syspass.org
|
||||
* @copyright 2012-2017, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
* sysPass is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* sysPass is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace SP\Mgmt\ApiTokens;
|
||||
|
||||
use SP\Core\Acl;
|
||||
use SP\DataModel\ItemSearchData;
|
||||
use SP\Mgmt\ItemSearchInterface;
|
||||
use SP\Storage\DB;
|
||||
use SP\Storage\QueryData;
|
||||
|
||||
/**
|
||||
* Class ApiTokenSearch
|
||||
*
|
||||
* @package SP\Mgmt\ApiTokens
|
||||
*/
|
||||
class ApiTokenSearch extends ApiTokenBase implements ItemSearchInterface
|
||||
{
|
||||
/**
|
||||
* @param ItemSearchData $SearchData
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMgmtSearch(ItemSearchData $SearchData)
|
||||
{
|
||||
$query = 'SELECT authtoken_id,' .
|
||||
'authtoken_userId,' .
|
||||
'authtoken_actionId, ' .
|
||||
'authtoken_token, ' .
|
||||
'user_login ' .
|
||||
'FROM authTokens ' .
|
||||
'LEFT JOIN usrData ON user_id = authtoken_userId ';
|
||||
|
||||
$Data = new QueryData();
|
||||
|
||||
if ($SearchData->getSeachString() !== '') {
|
||||
$search = '%' . $SearchData->getSeachString() . '%';
|
||||
$query .= ' WHERE user_login LIKE ?';
|
||||
|
||||
$Data->addParam($search);
|
||||
}
|
||||
|
||||
$query .= ' ORDER BY user_login';
|
||||
$query .= ' LIMIT ?, ?';
|
||||
|
||||
$Data->addParam($SearchData->getLimitStart());
|
||||
$Data->addParam($SearchData->getLimitCount());
|
||||
|
||||
$Data->setQuery($query);
|
||||
|
||||
DB::setFullRowCount();
|
||||
|
||||
$queryRes = DB::getResultsArray($Data);
|
||||
|
||||
foreach ($queryRes as $token) {
|
||||
$token->authtoken_actionId = Acl::getActionName($token->authtoken_actionId);
|
||||
}
|
||||
|
||||
$queryRes['count'] = $Data->getQueryNumRows();
|
||||
|
||||
return $queryRes;
|
||||
}
|
||||
}
|
||||
@@ -272,19 +272,18 @@ class DB
|
||||
/**
|
||||
* Método para registar los eventos de BD en el log
|
||||
*
|
||||
* @param $query string La consulta que genera el error
|
||||
* @param $errorMsg string El mensaje de error
|
||||
* @param $errorCode int El código de error
|
||||
* @param $queryFunction
|
||||
* @param string $query La consulta que genera el error
|
||||
* @param \Exception $e
|
||||
* @param string $queryFunction
|
||||
*/
|
||||
private static function logDBException($query, $errorMsg, $errorCode, $queryFunction)
|
||||
private static function logDBException($query, \Exception $e, $queryFunction)
|
||||
{
|
||||
$caller = Util::traceLastCall($queryFunction);
|
||||
|
||||
$LogMessage = new LogMessage();
|
||||
$LogMessage->setAction($caller);
|
||||
$LogMessage->addDescription(__('Error en la consulta', false));
|
||||
$LogMessage->addDescription(sprintf('%s (%s)', $errorMsg, $errorCode));
|
||||
$LogMessage->addDescription(sprintf('%s (%s)', $e->getMessage(), $e->getCode()));
|
||||
$LogMessage->addDetails('SQL', DBUtil::escape($query));
|
||||
|
||||
debugLog($LogMessage->getDescription(), true);
|
||||
@@ -345,7 +344,7 @@ class DB
|
||||
} catch (SPException $e) {
|
||||
$queryData->setQueryStatus($e->getCode());
|
||||
|
||||
self::logDBException($queryData->getQuery(), $e->getMessage(), $e->getCode(), __FUNCTION__);
|
||||
self::logDBException($queryData->getQuery(), $e, __FUNCTION__);
|
||||
|
||||
if ($e->getCode() === 23000) {
|
||||
throw new ConstraintException(SPException::SP_ERROR, __('Restricción de integridad', false), $e->getMessage(), $e->getCode());
|
||||
|
||||
@@ -7,4 +7,8 @@ ALTER TABLE `customFieldsData`
|
||||
ALTER TABLE `usrData`
|
||||
CHANGE COLUMN `user_mPass` `user_mPass` VARBINARY(1000) NULL DEFAULT NULL,
|
||||
CHANGE COLUMN `user_mIV` `user_mKey` VARBINARY(1000) NULL DEFAULT NULL;
|
||||
ALTER TABLE `authTokens`
|
||||
ADD COLUMN `authtoken_pass` VARBINARY(1000) NULL,
|
||||
ADD COLUMN `authtoken_key` VARBINARY(1000) NULL,
|
||||
ADD COLUMN `authtoken_hash` VARBINARY(100) NULL;
|
||||
|
||||
|
||||
@@ -530,8 +530,8 @@ pre, code, samp, kbd {
|
||||
padding: .3em 0; }
|
||||
|
||||
#box-popup {
|
||||
min-width: 25em;
|
||||
max-width: 50em;
|
||||
min-width: 30em;
|
||||
max-width: 60em;
|
||||
margin: 5em auto;
|
||||
padding: 0;
|
||||
background-color: #fff; }
|
||||
|
||||
2
inc/themes/material-blue/css/styles.min.css
vendored
2
inc/themes/material-blue/css/styles.min.css
vendored
File diff suppressed because one or more lines are too long
@@ -532,8 +532,8 @@
|
||||
}
|
||||
|
||||
#box-popup {
|
||||
min-width: 25em;
|
||||
max-width: 50em;
|
||||
min-width: 30em;
|
||||
max-width: 60em;
|
||||
margin: 5em auto;
|
||||
padding: 0;
|
||||
background-color: #fff;
|
||||
|
||||
@@ -114,9 +114,12 @@ sysPass.Theme = function (Common) {
|
||||
// Poner la clave en los input y actualizar MDL
|
||||
$dstParent.find("input:password").val(genPassword);
|
||||
$dstParent.addClass(mdl.CssClasses_.IS_DIRTY).removeClass(mdl.CssClasses_.IS_INVALID);
|
||||
|
||||
// Poner la clave en el input de repetición y encriptarla
|
||||
$targetR.val(genPassword).parent().addClass(mdl.CssClasses_.IS_DIRTY).removeClass(mdl.CssClasses_.IS_INVALID);
|
||||
Common.encryptFormValue($targetR);
|
||||
if ($targetR.length > 0) {
|
||||
$targetR.val(genPassword).parent().addClass(mdl.CssClasses_.IS_DIRTY).removeClass(mdl.CssClasses_.IS_INVALID);
|
||||
Common.encryptFormValue($targetR);
|
||||
}
|
||||
|
||||
// Mostar el indicador de complejidad
|
||||
$dstParent.find("#passLevel").show(500);
|
||||
@@ -127,8 +130,6 @@ sysPass.Theme = function (Common) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// FIXME
|
||||
// Diálogo de configuración de complejidad de clave
|
||||
var complexityDialog = function () {
|
||||
|
||||
@@ -193,8 +194,6 @@ sysPass.Theme = function (Common) {
|
||||
|
||||
var $thisParent = $this.parent();
|
||||
var targetId = $this.attr("id");
|
||||
var $targetIdR = $("#" + targetId + "R");
|
||||
|
||||
|
||||
var btnMenu = "<button id=\"menu-speed-" + targetId + "\" class=\"mdl-button mdl-js-button mdl-button--icon\" type=\"button\" title=\"" + Common.config().LANG[27] + "\"><i class=\"material-icons\">more_vert</i></button>";
|
||||
|
||||
@@ -234,7 +233,12 @@ sysPass.Theme = function (Common) {
|
||||
// Reset de los campos de clave
|
||||
$passwordActions.find(".reset").on("click", function () {
|
||||
$this.val("");
|
||||
$targetIdR.val("");
|
||||
|
||||
var $targetIdR = $("#" + targetId + "R");
|
||||
|
||||
if ($targetIdR.length > 0) {
|
||||
$targetIdR.val("");
|
||||
}
|
||||
|
||||
// Actualizar objetos de MDL
|
||||
componentHandler.upgradeDom();
|
||||
|
||||
18
inc/themes/material-blue/js/app-theme.min.js
vendored
18
inc/themes/material-blue/js/app-theme.min.js
vendored
@@ -1,18 +1,18 @@
|
||||
var $jscomp={scope:{},findInternal:function(a,g,e){a instanceof String&&(a=String(a));for(var h=a.length,k=0;k<h;k++){var m=a[k];if(g.call(e,m,k,a))return{i:k,v:m}}return{i:-1,v:void 0}}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(a,g,e){if(e.get||e.set)throw new TypeError("ES3 does not support getters and setters.");a!=Array.prototype&&a!=Object.prototype&&(a[g]=e.value)};
|
||||
$jscomp.getGlobal=function(a){return"undefined"!=typeof window&&window===a?a:"undefined"!=typeof global&&null!=global?global:a};$jscomp.global=$jscomp.getGlobal(this);$jscomp.polyfill=function(a,g,e,h){if(g){e=$jscomp.global;a=a.split(".");for(h=0;h<a.length-1;h++){var k=a[h];k in e||(e[k]={});e=e[k]}a=a[a.length-1];h=e[a];g=g(h);g!=h&&null!=g&&$jscomp.defineProperty(e,a,{configurable:!0,writable:!0,value:g})}};
|
||||
var $jscomp={scope:{},findInternal:function(a,g,e){a instanceof String&&(a=String(a));for(var h=a.length,k=0;k<h;k++){var l=a[k];if(g.call(e,l,k,a))return{i:k,v:l}}return{i:-1,v:void 0}}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(a,g,e){if(e.get||e.set)throw new TypeError("ES3 does not support getters and setters.");a!=Array.prototype&&a!=Object.prototype&&(a[g]=e.value)};
|
||||
$jscomp.getGlobal=function(a){return"undefined"!=typeof window&&window===a?a:"undefined"!=typeof global?global:a};$jscomp.global=$jscomp.getGlobal(this);$jscomp.polyfill=function(a,g,e,h){if(g){e=$jscomp.global;a=a.split(".");for(h=0;h<a.length-1;h++){var k=a[h];k in e||(e[k]={});e=e[k]}a=a[a.length-1];h=e[a];g=g(h);g!=h&&null!=g&&$jscomp.defineProperty(e,a,{configurable:!0,writable:!0,value:g})}};
|
||||
$jscomp.polyfill("Array.prototype.find",function(a){return a?a:function(a,e){return $jscomp.findInternal(this,a,e).v}},"es6-impl","es3");
|
||||
sysPass.Theme=function(a){var g=a.log,e={elems:{$wrap:$("#wrap-loading"),$loading:$("#loading")},show:function(a){void 0!==a&&!0===a&&e.elems.$wrap.addClass("overlay-full");e.elems.$wrap.show();e.elems.$loading.addClass("is-active")},hide:function(){e.elems.$wrap.removeClass("overlay-full").hide();e.elems.$loading.removeClass("is-active")},upgradeFull:function(){e.elems.$wrap.addClass("overlay-full")}},h=function(b){for(var d=0,f="",c;d<a.passwordData.complexity.numlength;)c=Math.floor(100*Math.random())%
|
||||
94+33,!a.passwordData.complexity.symbols&&(33<=c&&47>=c||58<=c&&64>=c||91<=c&&96>=c||123<=c&&126>=c)||!a.passwordData.complexity.numbers&&48<=c&&57>=c||!a.passwordData.complexity.uppercase&&65<=c&&90>=c||(d++,f+=String.fromCharCode(c));$("#viewPass").attr("title",f);var e=zxcvbn(f);a.passwordData.passLength=f.length;b?(d=b.parent(),c=$("#"+b.attr("id")+"R"),a.outputResult(e,b),b=new MaterialTextfield,d.find("input:password").val(f),d.addClass(b.CssClasses_.IS_DIRTY).removeClass(b.CssClasses_.IS_INVALID),
|
||||
c.val(f).parent().addClass(b.CssClasses_.IS_DIRTY).removeClass(b.CssClasses_.IS_INVALID),a.encryptFormValue(c),d.find("#passLevel").show(500)):(a.outputResult(e),$("input:password, input.password").val(f),$("#passLevel").show(500))},k=function(){var b='<div id="box-complexity"><div><label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="checkbox-numbers"><input type="checkbox" id="checkbox-numbers" class="mdl-checkbox__input" name="checkbox-numbers" checked/><span class="mdl-checkbox__label">'+
|
||||
0<c.length&&(c.val(f).parent().addClass(b.CssClasses_.IS_DIRTY).removeClass(b.CssClasses_.IS_INVALID),a.encryptFormValue(c)),d.find("#passLevel").show(500)):(a.outputResult(e),$("input:password, input.password").val(f),$("#passLevel").show(500))},k=function(){var b='<div id="box-complexity"><div><label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="checkbox-numbers"><input type="checkbox" id="checkbox-numbers" class="mdl-checkbox__input" name="checkbox-numbers" checked/><span class="mdl-checkbox__label">'+
|
||||
a.config().LANG[35]+'</span></label><label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="checkbox-uppercase"><input type="checkbox" id="checkbox-uppercase" class="mdl-checkbox__input" name="checkbox-uppercase"/><span class="mdl-checkbox__label">'+a.config().LANG[36]+'</span></label><label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="checkbox-symbols"><input type="checkbox" id="checkbox-symbols" class="mdl-checkbox__input" name="checkbox-symbols"/><span class="mdl-checkbox__label">'+
|
||||
a.config().LANG[37]+'</span></label><div class="mdl-textfield mdl-js-textfield textfield-passlength"><input class="mdl-textfield__input" type="number" pattern="[0-9]*" id="passlength" /><label class="mdl-textfield__label" for="passlength">'+a.config().LANG[38]+"</label></div></div></div>";showDialog({title:a.config().LANG[29],text:b,negative:{title:a.config().LANG[44]},positive:{title:a.config().LANG[43],onClick:function(d){d.preventDefault();a.passwordData.complexity.numbers=$("#checkbox-numbers").is(":checked");
|
||||
a.passwordData.complexity.uppercase=$("#checkbox-uppercase").is(":checked");a.passwordData.complexity.symbols=$("#checkbox-symbols").is(":checked");a.passwordData.complexity.numlength=parseInt($("#passlength").val())}},cancelable:!0,contentStyle:{"max-width":"300px"},onLoaded:function(){$("#checkbox-numbers").prop("checked",a.passwordData.complexity.numbers);$("#checkbox-uppercase").prop("checked",a.passwordData.complexity.uppercase);$("#checkbox-symbols").prop("checked",a.passwordData.complexity.symbols);
|
||||
$("#passlength").val(a.passwordData.complexity.numlength)}})},m=function(b){b.find(".passwordfield__input").each(function(){var d=$(this);if("true"!==d.attr("data-pass-upgraded")){var f=d.parent(),c=d.attr("id"),b=$("#"+c+"R"),l='<button id="menu-speed-'+c+'" class="mdl-button mdl-js-button mdl-button--icon" type="button" title="'+a.config().LANG[27]+'"><i class="material-icons">more_vert</i></button>',l=l+('<ul class="mdl-menu mdl-js-menu" for="menu-speed-'+c+'">')+('<li class="mdl-menu__item passGen"><i class="material-icons">settings</i>'+
|
||||
a.config().LANG[28]+"</li>"),l=l+('<li class="mdl-menu__item passComplexity"><i class="material-icons">vpn_key</i>'+a.config().LANG[29]+"</li>"),l=l+('<li class="mdl-menu__item reset"><i class="material-icons">refresh</i>'+a.config().LANG[30]+"</li>");f.after('<div class="password-actions" />');f.next(".password-actions").prepend('<span class="passLevel passLevel-'+c+' fullround" title="'+a.config().LANG[31]+'"></span>').prepend('<i class="showpass material-icons" title="'+a.config().LANG[32]+'">remove_red_eye</i>').prepend(l);
|
||||
d.on("keyup",function(){a.checkPassLevel(d)});f=d.parent().next();f.find(".passGen").on("click",function(){h(d);d.focus()});f.find(".passComplexity").on("click",function(){k()});f.find(".showpass").on("mouseover",function(){$(this).attr("title",d.val())});f.find(".reset").on("click",function(){d.val("");b.val("");componentHandler.upgradeDom()});d.attr("data-pass-upgraded","true")}});b.find(".passwordfield__input-show").each(function(){var b=$(this),f=$('<i class="showpass material-icons" title="'+
|
||||
a.config().LANG[32]+'" data-targetid="'+b.attr("id")+'">remove_red_eye</i>'),c=$('<i class="clip-pass-icon material-icons" title="'+a.config().LANG[34]+'" data-clipboard-text="'+b.val()+'">content_paste</i>');b.parent().after(c).after(f);f.on("mouseover",function(){f.attr("title",b.val())})})},n=function(b){g.info("setupDatePicker");var d={format:"YYYY-MM-DD",lang:a.config().LOCALE.substr(0,2),time:!1,cancelText:a.config().LANG[44],okText:a.config().LANG[43],clearText:a.config().LANG[30],nowText:a.config().LANG[56],
|
||||
$("#passlength").val(a.passwordData.complexity.numlength)}})},l=function(b){b.find(".passwordfield__input").each(function(){var d=$(this);if("true"!==d.attr("data-pass-upgraded")){var f=d.parent(),c=d.attr("id"),b='<button id="menu-speed-'+c+'" class="mdl-button mdl-js-button mdl-button--icon" type="button" title="'+a.config().LANG[27]+'"><i class="material-icons">more_vert</i></button>',b=b+('<ul class="mdl-menu mdl-js-menu" for="menu-speed-'+c+'">')+('<li class="mdl-menu__item passGen"><i class="material-icons">settings</i>'+
|
||||
a.config().LANG[28]+"</li>"),b=b+('<li class="mdl-menu__item passComplexity"><i class="material-icons">vpn_key</i>'+a.config().LANG[29]+"</li>"),b=b+('<li class="mdl-menu__item reset"><i class="material-icons">refresh</i>'+a.config().LANG[30]+"</li>");f.after('<div class="password-actions" />');f.next(".password-actions").prepend('<span class="passLevel passLevel-'+c+' fullround" title="'+a.config().LANG[31]+'"></span>').prepend('<i class="showpass material-icons" title="'+a.config().LANG[32]+'">remove_red_eye</i>').prepend(b);
|
||||
d.on("keyup",function(){a.checkPassLevel(d)});f=d.parent().next();f.find(".passGen").on("click",function(){h(d);d.focus()});f.find(".passComplexity").on("click",function(){k()});f.find(".showpass").on("mouseover",function(){$(this).attr("title",d.val())});f.find(".reset").on("click",function(){d.val("");var a=$("#"+c+"R");0<a.length&&a.val("");componentHandler.upgradeDom()});d.attr("data-pass-upgraded","true")}});b.find(".passwordfield__input-show").each(function(){var b=$(this),f=$('<i class="showpass material-icons" title="'+
|
||||
a.config().LANG[32]+'" data-targetid="'+b.attr("id")+'">remove_red_eye</i>'),c=$('<i class="clip-pass-icon material-icons" title="'+a.config().LANG[34]+'" data-clipboard-text="'+b.val()+'">content_paste</i>');b.parent().after(c).after(f);f.on("mouseover",function(){f.attr("title",b.val())})})},m=function(b){g.info("setupDatePicker");var d={format:"YYYY-MM-DD",lang:a.config().LOCALE.substr(0,2),time:!1,cancelText:a.config().LANG[44],okText:a.config().LANG[43],clearText:a.config().LANG[30],nowText:a.config().LANG[56],
|
||||
minDate:new Date,triggerEvent:"dateIconClick"};b.find(".password-datefield__input").each(function(){var b=$(this);b.bootstrapMaterialDatePicker(d);b.parent().append("<input type='hidden' name='passworddatechange_unix' value='"+moment.tz(b.val(),a.config().TIMEZONE).format("X")+"' />");b.parent().next("i").on("click",function(){b.trigger("dateIconClick")});b.on("change",function(){var c;c=moment.tz(b.val(),a.config().TIMEZONE).format("X");b.parent().find("input[name='passworddatechange_unix']").val(c)})})};
|
||||
return{passwordDetect:m,password:h,viewsTriggers:{search:function(){var b=$("#frmSearch"),d=$("#res-content");b.find(".icon-searchfav").on("click",function(){var c=$(this).find("i"),d=b.find("input[name='searchfav']");0==d.val()?(c.addClass("mdl-color-text--amber-A200"),c.attr("title",a.config().LANG[53]),d.val(1)):(c.removeClass("mdl-color-text--amber-A200"),c.attr("title",a.config().LANG[52]),d.val(0));b.submit()});var e=b.find("#tags")[0],c=b.find(".search-filters-tags"),g=b.find("i.show-filter");
|
||||
return{passwordDetect:l,password:h,viewsTriggers:{search:function(){var b=$("#frmSearch"),d=$("#res-content");b.find(".icon-searchfav").on("click",function(){var c=$(this).find("i"),d=b.find("input[name='searchfav']");0==d.val()?(c.addClass("mdl-color-text--amber-A200"),c.attr("title",a.config().LANG[53]),d.val(1)):(c.removeClass("mdl-color-text--amber-A200"),c.attr("title",a.config().LANG[52]),d.val(0));b.submit()});var e=b.find("#tags")[0],c=b.find(".search-filters-tags"),g=b.find("i.show-filter");
|
||||
d.on("click","#data-search-header .sort-down,#data-search-header .sort-up",function(){var b=$(this);b.parent().find("a").addClass("filterOn");a.appActions().account.sort(b)}).on("click","#search-rows i.icon-favorite",function(){var b=$(this);a.appActions().account.savefavorite(b,function(){"on"===b.data("status")?(b.addClass("mdl-color-text--amber-A100"),b.attr("title",a.config().LANG[50]),b.html("star")):(b.removeClass("mdl-color-text--amber-A100"),b.attr("title",a.config().LANG[49]),b.html("star_border"))})}).on("click",
|
||||
"#search-rows span.tag",function(){c.is(":hidden")&&g.trigger("click");e.selectize.addItem($(this).data("tag-id"))});g.on("click",function(){var a=$(this);c.is(":hidden")?(c.slideDown("slow"),a.html(a.data("icon-up"))):(c.slideUp("slow"),a.html(a.data("icon-down")))});0<e.selectedOptions.length&&g.trigger("click")},common:function(a){m(a);n(a)}},loading:e,ajax:{complete:function(){g.info("ajax:complete");componentHandler.upgradeDom()}},html:{getList:function(a){var b=$('<ul class="ldap-list-item mdl-list"></ul>'),
|
||||
"#search-rows span.tag",function(){c.is(":hidden")&&g.trigger("click");e.selectize.addItem($(this).data("tag-id"))});g.on("click",function(){var a=$(this);c.is(":hidden")?(c.slideDown("slow"),a.html(a.data("icon-up"))):(c.slideUp("slow"),a.html(a.data("icon-down")))});0<e.selectedOptions.length&&g.trigger("click")},common:function(a){l(a);m(a)}},loading:e,ajax:{complete:function(){g.info("ajax:complete");componentHandler.upgradeDom()}},html:{getList:function(a){var b=$('<ul class="ldap-list-item mdl-list"></ul>'),
|
||||
e=$('<li class="mdl-list__item"></li>'),c=$('<span class="mdl-list__item-primary-content"></span>');a.forEach(function(a){var d=c.clone();d.append('<i class="material-icons mdl-list__item-icon">person</i>');d.append(a);a=e.clone().append(d);b.append(a)});return b},tabs:{add:function(a,d,e,c){a=$(a);var b="";1===c&&(a.parent().find("#tabs-"+d).addClass("is-active"),b="is-active");a.append('<a href="#tabs-'+d+'" class="mdl-tabs__tab '+b+'">'+e+"</a>")}}}}};
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
<?php
|
||||
/** @var \SP\DataModel\ApiTokenData $ApiTokenData */
|
||||
/** @var \SP\Core\UI\ThemeIconsBase $icons */
|
||||
?>
|
||||
<div id="box-popup">
|
||||
<h2 class="center"><?php echo $header; ?><i class="btn-popup-close material-icons">close</i></h2>
|
||||
|
||||
@@ -13,10 +17,10 @@
|
||||
<td class="valField">
|
||||
<div class="lowres-title"><?php echo __('Usuario'); ?></div>
|
||||
|
||||
<select id="selUsers" name="users" class="select-box" required>
|
||||
<select id="selUsers" name="users" class="select-box" required <?php echo $isDisabled; ?>>
|
||||
<option value=""><?php echo __('Seleccionar Usuario'); ?></option>
|
||||
<?php foreach ($users as $user): ?>
|
||||
<?php $selected = ($gotData && $user->id == $token->authtoken_userId) ? 'selected' : ''; ?>
|
||||
<?php $selected = ($user->id === $ApiTokenData->getAuthtokenUserId()) ? 'selected' : ''; ?>
|
||||
<option value="<?php echo $user->id; ?>" <?php echo $selected; ?>><?php echo $user->name; ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
@@ -28,16 +32,28 @@
|
||||
<div class="lowres-title"><?php echo __('Acción'); ?></div>
|
||||
|
||||
<select id="selActions" name="actions"
|
||||
class="select-box" required>
|
||||
class="select-box" required <?php echo $isDisabled; ?>>
|
||||
<option value=""><?php echo __('Seleccionar Acción'); ?></option>
|
||||
<?php foreach ($actions as $id => $name): ?>
|
||||
<?php $selected = ($gotData && $id == $token->authtoken_actionId) ? 'selected' : ''; ?>
|
||||
<?php $selected = ($id === $ApiTokenData->getAuthtokenActionId()) ? 'selected' : ''; ?>
|
||||
<option value="<?php echo $id; ?>" <?php echo $selected; ?>><?php echo $name; ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if (!$isView): ?>
|
||||
<tr>
|
||||
<td class="descField"><?php echo __('Clave'); ?></td>
|
||||
<td class="valField">
|
||||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
|
||||
<input id="pass" name="pass" type="password" required
|
||||
class="mdl-textfield__input passwordfield__input mdl-color-text--indigo-400"
|
||||
maxlength="50">
|
||||
<label class="mdl-textfield__label"
|
||||
for="pass"><?php echo __('Clave'); ?></label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="descField"><?php echo __('Opciones'); ?></td>
|
||||
<td class="valField">
|
||||
@@ -56,22 +72,22 @@
|
||||
<td class="valField">
|
||||
<div class="lowres-title"><?php echo __('Token'); ?></div>
|
||||
|
||||
<?php echo $gotData ? $token->authtoken_token : ''; ?>
|
||||
<?php echo $ApiTokenData->getAuthtokenToken(); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<input type="hidden" name="itemId" value="<?php echo $gotData ? $token->authtoken_id : ''; ?>"/>
|
||||
<input type="hidden" name="itemId" value="<?php echo $ApiTokenData->getAuthtokenId(); ?>"/>
|
||||
<input type="hidden" name="actionId" value="<?php echo $actionId; ?>"/>
|
||||
<input type="hidden" name="sk" value="">
|
||||
<input type="hidden" name="isAjax" value="1">
|
||||
</form>
|
||||
<div class="action-in-box">
|
||||
<button
|
||||
class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-button--colored <?php echo $icons->getIconSave()->getClassButton(); ?>"
|
||||
form="frmTokens" title="<?php echo $icons->getIconSave()->getTitle(); ?>">
|
||||
class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-button--colored <?php echo $icons->getIconSave()->getClassButton(); ?>"
|
||||
form="frmTokens" title="<?php echo $icons->getIconSave()->getTitle(); ?>">
|
||||
<i class="material-icons"><?php echo $icons->getIconSave()->getIcon(); ?></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user