mirror of
https://github.com/nuxsmin/sysPass.git
synced 2026-03-07 00:46:59 +01:00
chore: Create PublicLinkService tests.
Signed-off-by: Rubén D <nuxsmin@syspass.org>
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link https://syspass.org
|
||||
* @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
|
||||
* @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
namespace SP\Modules\Web\Controllers\PublicLink;
|
||||
|
||||
|
||||
use Exception;
|
||||
use SP\Core\Acl\ActionsInterface;
|
||||
use SP\Core\Events\Event;
|
||||
@@ -79,4 +78,4 @@ final class SaveCreateFromAccountController extends PublicLinkSaveBase
|
||||
return $this->returnJsonResponseException($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link https://syspass.org
|
||||
* @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
|
||||
* @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
@@ -53,7 +53,7 @@ abstract class ContextBase implements ContextInterface
|
||||
*
|
||||
* @throws ContextException
|
||||
*/
|
||||
public function setTrasientKey(string $key, $value)
|
||||
public function setTrasientKey(string $key, mixed $value)
|
||||
{
|
||||
// If the key starts with "_" it's a protected key, thus cannot be overwritten
|
||||
if (str_starts_with($key, '_')
|
||||
@@ -72,7 +72,7 @@ abstract class ContextBase implements ContextInterface
|
||||
* Gets an arbitrary key from the trasient collection.
|
||||
* This key is not bound to any known method or type
|
||||
*/
|
||||
public function getTrasientKey(string $key, $default = null)
|
||||
public function getTrasientKey(string $key, mixed $default = null): mixed
|
||||
{
|
||||
return is_numeric($default) ?
|
||||
(int)$this->trasient->get($key, $default)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link https://syspass.org
|
||||
* @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
|
||||
* @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
@@ -34,6 +34,8 @@ use SP\Domain\User\Services\UserLoginResponse;
|
||||
*/
|
||||
interface ContextInterface
|
||||
{
|
||||
const MASTER_PASSWORD_KEY = '_masterpass';
|
||||
|
||||
/**
|
||||
* @throws ContextException
|
||||
*/
|
||||
@@ -122,18 +124,18 @@ interface ContextInterface
|
||||
*
|
||||
* @throws ContextException
|
||||
*/
|
||||
public function setTrasientKey(string $key, $value);
|
||||
public function setTrasientKey(string $key, mixed $value);
|
||||
|
||||
/**
|
||||
* Gets an arbitrary key from the trasient collection.
|
||||
* This key is not bound to any known method or type
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
* @param mixed|null $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getTrasientKey(string $key, $default = null);
|
||||
public function getTrasientKey(string $key, mixed $default = null): mixed;
|
||||
|
||||
/**
|
||||
* Sets a temporary master password
|
||||
@@ -145,7 +147,7 @@ interface ContextInterface
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setPluginKey(string $pluginName, string $key, $value);
|
||||
public function setPluginKey(string $pluginName, string $key, mixed $value);
|
||||
|
||||
public function getPluginKey(string $pluginName, string $key): mixed;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link https://syspass.org
|
||||
* @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
|
||||
* @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
@@ -530,7 +530,7 @@ class SessionContext extends ContextBase
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function setPluginKey(string $pluginName, string $key, $value)
|
||||
public function setPluginKey(string $pluginName, string $key, mixed $value)
|
||||
{
|
||||
/** @var ContextCollection $ctxKey */
|
||||
$ctxKey = $this->getContextKey($pluginName, new ContextCollection());
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link https://syspass.org
|
||||
* @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
|
||||
* @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
@@ -227,7 +227,7 @@ class StatelessContext extends ContextBase
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function setPluginKey(string $pluginName, string $key, $value)
|
||||
public function setPluginKey(string $pluginName, string $key, mixed $value): mixed
|
||||
{
|
||||
$ctxKey = $this->getContextKey('plugins');
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link https://syspass.org
|
||||
* @copyright 2012-2021, Rubén Domínguez nuxsmin@$syspass.org
|
||||
* @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
namespace SP\Core\Crypt;
|
||||
|
||||
use Defuse\Crypto\Exception\CryptoException;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
@@ -34,35 +33,46 @@ use RuntimeException;
|
||||
*/
|
||||
final class Vault
|
||||
{
|
||||
private ?string $data = null;
|
||||
private ?string $key = null;
|
||||
private int $timeSet = 0;
|
||||
private int $timeUpdated = 0;
|
||||
private ?string $data = null;
|
||||
private ?string $key = null;
|
||||
private int $timeSet = 0;
|
||||
|
||||
public static function getInstance(): Vault
|
||||
private function __construct(private CryptInterface $crypt) {}
|
||||
|
||||
public static function factory(CryptInterface $crypt): Vault
|
||||
{
|
||||
return new self();
|
||||
return new self($crypt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerar la clave de sesión
|
||||
* Re-key this vault
|
||||
*
|
||||
* @throws CryptoException
|
||||
* @throws \SP\Core\Exceptions\CryptException
|
||||
*/
|
||||
public function reKey(string $newSeed, string $oldSeed): Vault
|
||||
{
|
||||
$this->timeUpdated = time();
|
||||
$sessionMPass = $this->getData($oldSeed);
|
||||
|
||||
$this->saveData($sessionMPass, $newSeed);
|
||||
|
||||
return $this;
|
||||
return $this->saveData($this->getData($oldSeed), $newSeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Devolver la clave maestra de la sesión
|
||||
* Create a new vault with the saved data
|
||||
*
|
||||
* @throws CryptoException
|
||||
* @throws \SP\Core\Exceptions\CryptException
|
||||
*/
|
||||
public function saveData($data, string $key): Vault
|
||||
{
|
||||
$vault = new Vault($this->crypt);
|
||||
$vault->timeSet = time();
|
||||
$vault->key = $this->crypt->makeSecuredKey($key);
|
||||
$vault->data = $this->crypt->encrypt($data, $vault->key, $key);
|
||||
|
||||
return $vault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data decrypted
|
||||
*
|
||||
* @throws \SP\Core\Exceptions\CryptException
|
||||
*/
|
||||
public function getData(string $key): string
|
||||
{
|
||||
@@ -70,41 +80,24 @@ final class Vault
|
||||
throw new RuntimeException('Either data or key must be set');
|
||||
}
|
||||
|
||||
return Crypt::decrypt($this->data, $this->key, $key);
|
||||
return $this->crypt->decrypt($this->data, $this->key, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Guardar la clave maestra en la sesión
|
||||
*
|
||||
* @throws CryptoException
|
||||
*/
|
||||
public function saveData($data, string $key): Vault
|
||||
{
|
||||
if ($this->timeSet === 0) {
|
||||
$this->timeSet = time();
|
||||
}
|
||||
|
||||
$this->key = Crypt::makeSecuredKey($key);
|
||||
$this->data = Crypt::encrypt($data, $this->key, $key);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTimeSet(): int
|
||||
{
|
||||
return $this->timeSet;
|
||||
}
|
||||
|
||||
public function getTimeUpdated(): int
|
||||
{
|
||||
return $this->timeUpdated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializaes the current object
|
||||
* Serialize the current vault
|
||||
*/
|
||||
public function getSerialized(): string
|
||||
{
|
||||
return serialize($this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last time the key and data were set
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTimeSet(): int
|
||||
{
|
||||
return $this->timeSet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link https://syspass.org
|
||||
* @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
|
||||
* @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
@@ -31,9 +31,9 @@ namespace SP\DataModel;
|
||||
*/
|
||||
class PublicLinkListData extends PublicLinkData
|
||||
{
|
||||
protected ?string $userName;
|
||||
protected ?string $userLogin;
|
||||
protected ?string $accountName;
|
||||
protected ?string $userName = null;
|
||||
protected ?string $userLogin = null;
|
||||
protected ?string $accountName = null;
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link https://syspass.org
|
||||
* @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
|
||||
* @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
@@ -27,7 +27,7 @@ namespace SP\Domain\Account\Services;
|
||||
use Defuse\Crypto\Exception\CryptoException;
|
||||
use Defuse\Crypto\Exception\EnvironmentIsBrokenException;
|
||||
use SP\Core\Application;
|
||||
use SP\Core\Crypt\Crypt;
|
||||
use SP\Core\Crypt\CryptInterface;
|
||||
use SP\Core\Crypt\Vault;
|
||||
use SP\Core\Exceptions\ConstraintException;
|
||||
use SP\Core\Exceptions\QueryException;
|
||||
@@ -38,6 +38,7 @@ use SP\DataModel\PublicLinkListData;
|
||||
use SP\Domain\Account\Ports\AccountServiceInterface;
|
||||
use SP\Domain\Account\Ports\PublicLinkRepositoryInterface;
|
||||
use SP\Domain\Account\Ports\PublicLinkServiceInterface;
|
||||
use SP\Domain\Common\Models\Simple;
|
||||
use SP\Domain\Common\Services\Service;
|
||||
use SP\Domain\Common\Services\ServiceException;
|
||||
use SP\Domain\Common\Services\ServiceItemTrait;
|
||||
@@ -62,21 +63,14 @@ final class PublicLinkService extends Service implements PublicLinkServiceInterf
|
||||
*/
|
||||
public const TYPE_ACCOUNT = 1;
|
||||
|
||||
private PublicLinkRepositoryInterface $publicLinkRepository;
|
||||
private RequestInterface $request;
|
||||
private AccountServiceInterface $accountService;
|
||||
|
||||
public function __construct(
|
||||
Application $application,
|
||||
PublicLinkRepositoryInterface $publicLinkRepository,
|
||||
RequestInterface $request,
|
||||
AccountServiceInterface $accountService
|
||||
private PublicLinkRepositoryInterface $publicLinkRepository,
|
||||
private RequestInterface $request,
|
||||
private AccountServiceInterface $accountService,
|
||||
private CryptInterface $crypt
|
||||
) {
|
||||
parent::__construct($application);
|
||||
|
||||
$this->publicLinkRepository = $publicLinkRepository;
|
||||
$this->request = $request;
|
||||
$this->accountService = $accountService;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,11 +89,6 @@ final class PublicLinkService extends Service implements PublicLinkServiceInterf
|
||||
return hash('sha256', uniqid('sysPassPublicLink', true));
|
||||
}
|
||||
|
||||
public static function getKeyForHash(string $salt, PublicLinkData $publicLinkData): string
|
||||
{
|
||||
return sha1($salt.$publicLinkData->getHash());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SP\DataModel\ItemSearchData $itemSearchData
|
||||
*
|
||||
@@ -127,22 +116,15 @@ final class PublicLinkService extends Service implements PublicLinkServiceInterf
|
||||
throw new NoSuchItemException(__u('Link not found'));
|
||||
}
|
||||
|
||||
$key = $this->getPublicLinkKey();
|
||||
|
||||
/** @var PublicLinkData $publicLinkData */
|
||||
$publicLinkData = $result->getData();
|
||||
$publicLinkData->setHash($key->getHash());
|
||||
$publicLinkData->setData($this->getSecuredLinkData($publicLinkData->getItemId(), $key));
|
||||
$publicLinkData->setDateExpire(self::calcDateExpire($this->config));
|
||||
$publicLinkData->setMaxCountViews($this->config->getConfigData()->getPublinksMaxViews());
|
||||
|
||||
return $this->publicLinkRepository->refresh($publicLinkData);
|
||||
return $this->publicLinkRepository
|
||||
->refresh($this->buildPublicLink(PublicLinkData::buildFromSimpleModel($result->getData())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return \SP\DataModel\PublicLinkListData
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
* @throws \SP\Infrastructure\Common\Repositories\NoSuchItemException
|
||||
*/
|
||||
public function getById(int $id): PublicLinkListData
|
||||
@@ -153,7 +135,36 @@ final class PublicLinkService extends Service implements PublicLinkServiceInterf
|
||||
throw new NoSuchItemException(__u('Link not found'));
|
||||
}
|
||||
|
||||
return $result->getData();
|
||||
return PublicLinkListData::buildFromSimpleModel($result->getData());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \SP\DataModel\PublicLinkData $publicLinkData
|
||||
*
|
||||
* @return \SP\DataModel\PublicLinkData
|
||||
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \SP\Core\Exceptions\CryptException
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \SP\Domain\Common\Services\ServiceException
|
||||
* @throws \SP\Infrastructure\Common\Repositories\NoSuchItemException
|
||||
*/
|
||||
private function buildPublicLink(PublicLinkData $publicLinkData): PublicLinkData
|
||||
{
|
||||
$key = $this->getPublicLinkKey();
|
||||
|
||||
$publicLinkDataClone = clone $publicLinkData;
|
||||
|
||||
$publicLinkDataClone->setHash($key->getHash());
|
||||
$publicLinkDataClone->setData($this->getSecuredLinkData($publicLinkDataClone->getItemId(), $key));
|
||||
$publicLinkDataClone->setDateExpire(self::calcDateExpire($this->config));
|
||||
$publicLinkDataClone->setMaxCountViews($this->config->getConfigData()->getPublinksMaxViews());
|
||||
|
||||
if ($publicLinkDataClone->getUserId() === null) {
|
||||
$publicLinkDataClone->setUserId($this->context->getUserData()->getId());
|
||||
}
|
||||
|
||||
return $publicLinkDataClone;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,28 +181,30 @@ final class PublicLinkService extends Service implements PublicLinkServiceInterf
|
||||
/**
|
||||
* Obtener los datos de una cuenta y encriptarlos para el enlace
|
||||
*
|
||||
* @throws \Defuse\Crypto\Exception\CryptoException
|
||||
* @param int $itemId
|
||||
* @param \SP\Domain\Account\Services\PublicLinkKey $key
|
||||
*
|
||||
* @return string
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \SP\Core\Exceptions\CryptException
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \SP\Infrastructure\Common\Repositories\NoSuchItemException
|
||||
* @throws \SP\Domain\Common\Services\ServiceException
|
||||
* @throws \SP\Infrastructure\Common\Repositories\NoSuchItemException
|
||||
*/
|
||||
private function getSecuredLinkData(int $itemId, PublicLinkKey $key): string
|
||||
{
|
||||
// Obtener los datos de la cuenta
|
||||
$accountData = $this->accountService->getDataForLink($itemId);
|
||||
|
||||
// Desencriptar la clave de la cuenta
|
||||
$accountData->setPass(
|
||||
Crypt::decrypt(
|
||||
$accountData->getPass(),
|
||||
$accountData->getKey(),
|
||||
$accountDataClone = $accountData->mutate([
|
||||
'pass' => $this->crypt->decrypt(
|
||||
$accountData['pass'],
|
||||
$accountData['key'],
|
||||
$this->getMasterKeyFromContext()
|
||||
)
|
||||
);
|
||||
$accountData->setKey(null);
|
||||
),
|
||||
'key' => null,
|
||||
]);
|
||||
|
||||
return (new Vault())->saveData(serialize($accountData), $key->getKey())->getSerialized();
|
||||
return Vault::factory($this->crypt)->saveData(serialize($accountDataClone), $key->getKey())->getSerialized();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -244,25 +257,15 @@ final class PublicLinkService extends Service implements PublicLinkServiceInterf
|
||||
*/
|
||||
public function create(PublicLinkData $itemData): int
|
||||
{
|
||||
$key = $this->getPublicLinkKey();
|
||||
|
||||
$itemData->setHash($key->getHash());
|
||||
$itemData->setData($this->getSecuredLinkData($itemData->getItemId(), $key));
|
||||
$itemData->setDateExpire(self::calcDateExpire($this->config));
|
||||
$itemData->setMaxCountViews($this->config->getConfigData()->getPublinksMaxViews());
|
||||
$itemData->setUserId($this->context->getUserData()->getId());
|
||||
|
||||
return $this->publicLinkRepository->create($itemData)->getLastId();
|
||||
return $this->publicLinkRepository->create($this->buildPublicLink($itemData))->getLastId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all items from the service's repository
|
||||
*
|
||||
* @return PublicLinkListData[]
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function getAllBasic(): array
|
||||
{
|
||||
return $this->publicLinkRepository->getAll()->getDataAsArray();
|
||||
throw new ServiceException(__u('Not implemented'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -272,15 +275,30 @@ final class PublicLinkService extends Service implements PublicLinkServiceInterf
|
||||
*
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \SP\Domain\Common\Services\ServiceException
|
||||
*/
|
||||
public function addLinkView(PublicLinkData $publicLinkData): void
|
||||
{
|
||||
/** @var array $useInfo */
|
||||
$useInfo = unserialize($publicLinkData->getUseInfo(), false);
|
||||
$useInfo[] = self::getUseInfo($publicLinkData->getHash(), $this->request);
|
||||
$publicLinkData->setUseInfo($useInfo);
|
||||
$useInfo = array();
|
||||
|
||||
$this->publicLinkRepository->addLinkView($publicLinkData);
|
||||
if (empty($publicLinkData->getHash())) {
|
||||
throw new ServiceException(__u('Public link hash not set'));
|
||||
}
|
||||
|
||||
if (!empty($publicLinkData->getUseInfo())) {
|
||||
$publicLinkUseInfo = unserialize($publicLinkData->getUseInfo(), ['allowed_classes' => false]);
|
||||
|
||||
if (is_array($publicLinkUseInfo)) {
|
||||
$useInfo = $publicLinkUseInfo;
|
||||
}
|
||||
}
|
||||
|
||||
$useInfo[] = self::getUseInfo($publicLinkData->getHash(), $this->request);
|
||||
|
||||
$publicLinkDataClone = clone $publicLinkData;
|
||||
$publicLinkDataClone->setUseInfo($useInfo);
|
||||
|
||||
$this->publicLinkRepository->addLinkView($publicLinkDataClone);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -308,7 +326,7 @@ final class PublicLinkService extends Service implements PublicLinkServiceInterf
|
||||
throw new NoSuchItemException(__u('Link not found'));
|
||||
}
|
||||
|
||||
return $result->getData();
|
||||
return PublicLinkData::buildFromSimpleModel($result->getData(Simple::class));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -317,6 +335,7 @@ final class PublicLinkService extends Service implements PublicLinkServiceInterf
|
||||
* @param int $itemId
|
||||
*
|
||||
* @return \SP\DataModel\PublicLinkData
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
* @throws \SP\Infrastructure\Common\Repositories\NoSuchItemException
|
||||
*/
|
||||
public function getHashForItem(int $itemId): PublicLinkData
|
||||
@@ -327,7 +346,7 @@ final class PublicLinkService extends Service implements PublicLinkServiceInterf
|
||||
throw new NoSuchItemException(__u('Link not found'));
|
||||
}
|
||||
|
||||
return $result->getData();
|
||||
return PublicLinkData::buildFromSimpleModel($result->getData(Simple::class));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,11 +29,10 @@ use JsonSerializable;
|
||||
/**
|
||||
* Class DataModel
|
||||
*/
|
||||
abstract class Model implements JsonSerializable
|
||||
abstract class Model implements JsonSerializable, \ArrayAccess
|
||||
{
|
||||
private ?array $fields = null;
|
||||
/**
|
||||
* Dynamically declared properties must not be class' properties
|
||||
* Dynamically declared properties. Must not be class' properties
|
||||
*/
|
||||
private array $properties = [];
|
||||
|
||||
@@ -100,8 +99,6 @@ abstract class Model implements JsonSerializable
|
||||
$fields = array_diff_key($fields, array_flip($filter));
|
||||
}
|
||||
|
||||
$this->fields = array_keys($fields);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
@@ -168,24 +165,21 @@ abstract class Model implements JsonSerializable
|
||||
return $this->toArray();
|
||||
}
|
||||
|
||||
public function getFields(): ?array
|
||||
{
|
||||
return $this->fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get non-class properties
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __get(string $name)
|
||||
{
|
||||
if (array_key_exists($name, $this->properties)) {
|
||||
return $this->properties[$name];
|
||||
}
|
||||
$this->offsetGet($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set non-class properties
|
||||
*
|
||||
* @param string $name
|
||||
* @param $value
|
||||
*
|
||||
@@ -193,6 +187,62 @@ abstract class Model implements JsonSerializable
|
||||
*/
|
||||
public function __set(string $name, $value): void
|
||||
{
|
||||
$this->properties[$name] = $value;
|
||||
$this->offsetSet($name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get non-class properties
|
||||
*
|
||||
* @param mixed $offset
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function offsetGet(mixed $offset): mixed
|
||||
{
|
||||
return $this->properties[$offset];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set non-class properties
|
||||
*
|
||||
* @param mixed $offset
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function offsetSet(mixed $offset, mixed $value): void
|
||||
{
|
||||
$this->properties[$offset] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether an offset exists in non-class properties
|
||||
*
|
||||
* @link https://php.net/manual/en/arrayaccess.offsetexists.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* An offset to check for.
|
||||
* </p>
|
||||
*
|
||||
* @return bool true on success or false on failure.
|
||||
* </p>
|
||||
* <p>
|
||||
* The return value will be casted to boolean if non-boolean was returned.
|
||||
*/
|
||||
public function offsetExists(mixed $offset): bool
|
||||
{
|
||||
return array_key_exists($offset, $this->properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset a non-class property
|
||||
*
|
||||
* @param mixed $offset
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function offsetUnset(mixed $offset): void
|
||||
{
|
||||
unset($this->properties[$offset]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link https://syspass.org
|
||||
* @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
|
||||
* @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
@@ -64,7 +64,7 @@ abstract class Service
|
||||
if ($this->context instanceof SessionContext) {
|
||||
$key = Session::getSessionKey($this->context);
|
||||
} else {
|
||||
$key = $this->context->getTrasientKey('_masterpass');
|
||||
$key = $this->context->getTrasientKey(ContextInterface::MASTER_PASSWORD_KEY);
|
||||
}
|
||||
|
||||
if (empty($key)) {
|
||||
|
||||
@@ -29,6 +29,7 @@ use SP\Core\Exceptions\QueryException;
|
||||
use SP\Core\Exceptions\SPException;
|
||||
use SP\DataModel\ItemSearchData;
|
||||
use SP\DataModel\PublicLinkData;
|
||||
use SP\Domain\Account\Ports\PublicLinkRepositoryInterface;
|
||||
use SP\Infrastructure\Common\Repositories\DuplicatedItemException;
|
||||
use SP\Infrastructure\Common\Repositories\Repository;
|
||||
use SP\Infrastructure\Common\Repositories\RepositoryItemTrait;
|
||||
@@ -41,7 +42,7 @@ use function SP\__u;
|
||||
*
|
||||
* @package SP\Infrastructure\Common\Repositories\PublicLink
|
||||
*/
|
||||
final class PublicLinkRepository extends Repository implements \SP\Domain\Account\Ports\PublicLinkRepositoryInterface
|
||||
final class PublicLinkRepository extends Repository implements PublicLinkRepositoryInterface
|
||||
{
|
||||
use RepositoryItemTrait;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link https://syspass.org
|
||||
* @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
|
||||
* @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
@@ -94,7 +94,7 @@ class QueryResult
|
||||
private function checkDataType(?string $dataType = null): void
|
||||
{
|
||||
if (null !== $dataType && $this->dataType !== null && $dataType !== $this->dataType) {
|
||||
throw new SPException(sprintf(__u('Invalid data\'s type: %s - Expected: %s'), $dataType, $this->dataType));
|
||||
throw new SPException(sprintf(__u('Invalid data\'s type: %s - Current: %s'), $dataType, $this->dataType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
582
tests/SP/Domain/Account/Services/PublicLinkServiceTest.php
Normal file
582
tests/SP/Domain/Account/Services/PublicLinkServiceTest.php
Normal file
@@ -0,0 +1,582 @@
|
||||
<?php
|
||||
/*
|
||||
* sysPass
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link https://syspass.org
|
||||
* @copyright 2012-2023, 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\Tests\Domain\Account\Services;
|
||||
|
||||
use PHPUnit\Framework\Constraint\Callback;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use SP\Core\Context\ContextInterface;
|
||||
use SP\Core\Crypt\CryptInterface;
|
||||
use SP\DataModel\ItemSearchData;
|
||||
use SP\DataModel\PublicLinkData;
|
||||
use SP\Domain\Account\Ports\AccountServiceInterface;
|
||||
use SP\Domain\Account\Ports\PublicLinkRepositoryInterface;
|
||||
use SP\Domain\Account\Services\PublicLinkService;
|
||||
use SP\Domain\Common\Models\Simple;
|
||||
use SP\Domain\Common\Services\ServiceException;
|
||||
use SP\Http\RequestInterface;
|
||||
use SP\Infrastructure\Common\Repositories\NoSuchItemException;
|
||||
use SP\Infrastructure\Database\QueryResult;
|
||||
use SP\Tests\Generators\PublicLinkDataGenerator;
|
||||
use SP\Tests\UnitaryTestCase;
|
||||
|
||||
/**
|
||||
* Class PublicLinkServiceTest
|
||||
*
|
||||
* @group unitary
|
||||
*/
|
||||
class PublicLinkServiceTest extends UnitaryTestCase
|
||||
{
|
||||
|
||||
private PublicLinkRepositoryInterface|MockObject $publicLinkRepository;
|
||||
private RequestInterface|MockObject $request;
|
||||
private MockObject|PublicLinkService $publicLinkService;
|
||||
private CryptInterface|MockObject $crypt;
|
||||
private MockObject|AccountServiceInterface $accountService;
|
||||
|
||||
/**
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \SP\Domain\Common\Services\ServiceException
|
||||
*/
|
||||
public function testAddLinkView()
|
||||
{
|
||||
$publicLinkData = new PublicLinkData();
|
||||
$publicLinkData->setHash(self::$faker->sha1);
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('addLinkView')
|
||||
->with(
|
||||
new Callback(function (PublicLinkData $publicLinkData) {
|
||||
$useInfo = unserialize($publicLinkData->getUseInfo(), ['allowed_classes' => false]);
|
||||
|
||||
return is_array($useInfo) && count($useInfo) === 1;
|
||||
})
|
||||
);
|
||||
|
||||
$this->publicLinkService->addLinkView($publicLinkData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \SP\Domain\Common\Services\ServiceException
|
||||
*/
|
||||
public function testAddLinkViewWithoutHash()
|
||||
{
|
||||
$publicLinkData = new PublicLinkData();
|
||||
|
||||
$this->expectException(ServiceException::class);
|
||||
$this->expectExceptionMessage('Public link hash not set');
|
||||
|
||||
$this->publicLinkService->addLinkView($publicLinkData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \SP\Domain\Common\Services\ServiceException
|
||||
*/
|
||||
public function testAddLinkViewWithUseInfo()
|
||||
{
|
||||
$publicLinkData = new PublicLinkData();
|
||||
$publicLinkData->setHash(self::$faker->sha1);
|
||||
$publicLinkData->setUseInfo([
|
||||
[
|
||||
'who' => self::$faker->ipv4,
|
||||
'time' => time(),
|
||||
'hash' => self::$faker->sha1,
|
||||
'agent' => self::$faker->userAgent,
|
||||
'https' => self::$faker->boolean,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('addLinkView')
|
||||
->with(
|
||||
new Callback(function (PublicLinkData $publicLinkData) {
|
||||
$useInfo = unserialize($publicLinkData->getUseInfo(), ['allowed_classes' => false]);
|
||||
|
||||
return is_array($useInfo) && count($useInfo) === 2;
|
||||
})
|
||||
);
|
||||
|
||||
$this->publicLinkService->addLinkView($publicLinkData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function testGetByHash()
|
||||
{
|
||||
$hash = self::$faker->sha1;
|
||||
$publicLink = PublicLinkDataGenerator::factory()->buildPublicLink();
|
||||
$result = new QueryResult([new Simple($publicLink->toArray())]);
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('getByHash')
|
||||
->with($hash)
|
||||
->willReturn($result);
|
||||
|
||||
$actual = $this->publicLinkService->getByHash($hash);
|
||||
|
||||
$this->assertEquals($publicLink, $actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function testGetByHashNotFound()
|
||||
{
|
||||
$hash = self::$faker->sha1;
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('getByHash')
|
||||
->with($hash)
|
||||
->willReturn(new QueryResult([]));
|
||||
|
||||
$this->expectException(NoSuchItemException::class);
|
||||
$this->expectExceptionMessage('Link not found');
|
||||
|
||||
$this->publicLinkService->getByHash($hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \SP\Domain\Common\Services\ServiceException
|
||||
*/
|
||||
public function testDeleteByIdBatch()
|
||||
{
|
||||
$ids = array_map(fn() => self::$faker->randomNumber(), range(0, 9));
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('deleteByIdBatch')
|
||||
->with($ids)
|
||||
->willReturn(10);
|
||||
|
||||
$actual = $this->publicLinkService->deleteByIdBatch($ids);
|
||||
|
||||
$this->assertEquals(count($ids), $actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \SP\Domain\Common\Services\ServiceException
|
||||
*/
|
||||
public function testDeleteByIdBatchWithCountMismatch()
|
||||
{
|
||||
$ids = array_map(fn() => self::$faker->randomNumber(), range(0, 9));
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('deleteByIdBatch')
|
||||
->with($ids)
|
||||
->willReturn(1);
|
||||
|
||||
$this->expectException(ServiceException::class);
|
||||
$this->expectExceptionMessage('Error while removing the links');
|
||||
|
||||
$this->publicLinkService->deleteByIdBatch($ids);
|
||||
}
|
||||
|
||||
public function testCreateLinkHash()
|
||||
{
|
||||
$this->assertNotEmpty(PublicLinkService::createLinkHash());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function testUpdate()
|
||||
{
|
||||
$publicLinkList = PublicLinkDataGenerator::factory()->buildPublicLinkList();
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('update')
|
||||
->with($publicLinkList);
|
||||
|
||||
$this->publicLinkService->update($publicLinkList);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
*/
|
||||
public function testDelete()
|
||||
{
|
||||
$id = self::$faker->randomNumber();
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('delete')
|
||||
->with($id);
|
||||
|
||||
$this->publicLinkService->delete($id);
|
||||
}
|
||||
|
||||
public function testSearch()
|
||||
{
|
||||
$itemSearchData = new ItemSearchData(self::$faker->colorName);
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('search')
|
||||
->with($itemSearchData);
|
||||
|
||||
$this->publicLinkService->search($itemSearchData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \SP\Infrastructure\Common\Repositories\NoSuchItemException
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function testGetHashForItem()
|
||||
{
|
||||
$itemId = self::$faker->randomNumber();
|
||||
$publicLinkData = PublicLinkDataGenerator::factory()->buildPublicLink();
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('getHashForItem')
|
||||
->with($itemId)
|
||||
->willReturn(new QueryResult([new Simple($publicLinkData->toArray())]));
|
||||
|
||||
$actual = $this->publicLinkService->getHashForItem($itemId);
|
||||
|
||||
$this->assertEquals($publicLinkData, $actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \SP\Infrastructure\Common\Repositories\NoSuchItemException
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function testGetHashForItemNotFound()
|
||||
{
|
||||
$itemId = self::$faker->randomNumber();
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('getHashForItem')
|
||||
->with($itemId)
|
||||
->willReturn(new QueryResult([]));
|
||||
|
||||
$this->expectException(NoSuchItemException::class);
|
||||
$this->expectExceptionMessage('Link not found');
|
||||
|
||||
$this->publicLinkService->getHashForItem($itemId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Defuse\Crypto\Exception\CryptoException
|
||||
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
|
||||
* @throws \SP\Infrastructure\Common\Repositories\NoSuchItemException
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \SP\Domain\Common\Services\ServiceException
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function testRefresh()
|
||||
{
|
||||
$id = self::$faker->randomNumber();
|
||||
$publicLinkData = PublicLinkDataGenerator::factory()->buildPublicLink();
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('getById')
|
||||
->with($id)
|
||||
->willReturn(new QueryResult([new Simple($publicLinkData->toArray())]));
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('refresh')
|
||||
->with(
|
||||
new Callback(function (PublicLinkData $actual) use ($publicLinkData) {
|
||||
$filter = ['hash', 'dateExpire', 'maxCountViews', 'data'];
|
||||
|
||||
return $actual->toArray(null, $filter) === $publicLinkData->toArray(null, $filter)
|
||||
&& !empty($actual->getHash())
|
||||
&& !empty($actual->getDateExpire())
|
||||
&& !empty($actual->getMaxCountViews())
|
||||
&& !empty($actual->getData());
|
||||
})
|
||||
)
|
||||
->willReturn(true);
|
||||
|
||||
$passData = ['pass' => self::$faker->password, 'key' => self::$faker->sha1];
|
||||
|
||||
$this->accountService
|
||||
->expects(self::once())
|
||||
->method('getDataForLink')
|
||||
->with($publicLinkData->getItemId())
|
||||
->willReturn(new Simple($passData));
|
||||
|
||||
$this->crypt
|
||||
->expects(self::once())
|
||||
->method('decrypt')
|
||||
->with(
|
||||
$passData['pass'],
|
||||
$passData['key'],
|
||||
$this->context->getTrasientKey(ContextInterface::MASTER_PASSWORD_KEY)
|
||||
)
|
||||
->willReturn(self::$faker->password);
|
||||
|
||||
$actual = $this->publicLinkService->refresh($id);
|
||||
|
||||
$this->assertTrue($actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Defuse\Crypto\Exception\CryptoException
|
||||
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
|
||||
* @throws \SP\Infrastructure\Common\Repositories\NoSuchItemException
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \SP\Domain\Common\Services\ServiceException
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function testRefreshNotFound()
|
||||
{
|
||||
$id = self::$faker->randomNumber();
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('getById')
|
||||
->with($id)
|
||||
->willReturn(new QueryResult([]));
|
||||
|
||||
$this->expectException(NoSuchItemException::class);
|
||||
$this->expectExceptionMessage('Link not found');
|
||||
|
||||
$this->publicLinkService->refresh($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
|
||||
*/
|
||||
public function testGetPublicLinkKey()
|
||||
{
|
||||
$hash = self::$faker->sha1;
|
||||
|
||||
$actual = $this->publicLinkService->getPublicLinkKey($hash);
|
||||
|
||||
$this->assertEquals($hash, $actual->getHash());
|
||||
$this->assertNotEmpty($actual->getKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
|
||||
*/
|
||||
public function testGetPublicLinkKeyWithoutHash()
|
||||
{
|
||||
$actual = $this->publicLinkService->getPublicLinkKey();
|
||||
|
||||
$this->assertNotEmpty($actual->getHash());
|
||||
$this->assertNotEmpty($actual->getKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
* @throws \SP\Infrastructure\Common\Repositories\NoSuchItemException
|
||||
*/
|
||||
public function testGetById()
|
||||
{
|
||||
$itemId = self::$faker->randomNumber();
|
||||
$builPublicLinkList = PublicLinkDataGenerator::factory()->buildPublicLinkList();
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('getById')
|
||||
->with($itemId)
|
||||
->willReturn(new QueryResult([new Simple($builPublicLinkList->toArray())]));
|
||||
|
||||
$actual = $this->publicLinkService->getById($itemId);
|
||||
|
||||
$this->assertEquals($builPublicLinkList->toArray(null, ['clientName']), $actual->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
* @throws \SP\Infrastructure\Common\Repositories\NoSuchItemException
|
||||
*/
|
||||
public function testGetByIdNotFound()
|
||||
{
|
||||
$itemId = self::$faker->randomNumber();
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('getById')
|
||||
->with($itemId)
|
||||
->willReturn(new QueryResult([]));
|
||||
|
||||
$this->expectException(NoSuchItemException::class);
|
||||
$this->expectExceptionMessage('Link not found');
|
||||
|
||||
$this->publicLinkService->getById($itemId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function testGetAllBasic()
|
||||
{
|
||||
$this->expectException(ServiceException::class);
|
||||
$this->expectExceptionMessage('Not implemented');
|
||||
|
||||
$this->publicLinkService->getAllBasic();
|
||||
}
|
||||
|
||||
public function testGetUseInfo()
|
||||
{
|
||||
$hash = self::$faker->sha1;
|
||||
$who = self::$faker->ipv4;
|
||||
$userAgent = self::$faker->userAgent;
|
||||
|
||||
$request = $this->createMock(RequestInterface::class);
|
||||
|
||||
$request->expects(self::once())
|
||||
->method('getClientAddress')
|
||||
->with(true)
|
||||
->willReturn($who);
|
||||
|
||||
$request->expects(self::once())
|
||||
->method('getHeader')
|
||||
->with('User-Agent')
|
||||
->willReturn($userAgent);
|
||||
|
||||
$request->expects(self::once())
|
||||
->method('isHttps')
|
||||
->willReturn(true);
|
||||
|
||||
$actual = PublicLinkService::getUseInfo($hash, $request);
|
||||
|
||||
$this->assertArrayHasKey('who', $actual);
|
||||
$this->assertArrayHasKey('time', $actual);
|
||||
$this->assertArrayHasKey('hash', $actual);
|
||||
$this->assertArrayHasKey('agent', $actual);
|
||||
$this->assertArrayHasKey('https', $actual);
|
||||
$this->assertEquals($who, $actual['who']);
|
||||
$this->assertEquals($hash, $actual['hash']);
|
||||
$this->assertEquals($userAgent, $actual['agent']);
|
||||
$this->assertTrue($actual['https']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws \Defuse\Crypto\Exception\CryptoException
|
||||
* @throws \SP\Core\Exceptions\ConstraintException
|
||||
* @throws \SP\Core\Exceptions\QueryException
|
||||
* @throws \SP\Core\Exceptions\SPException
|
||||
*/
|
||||
public function testCreate()
|
||||
{
|
||||
$publicLinkData = PublicLinkDataGenerator::factory()->buildPublicLink();
|
||||
$result = new QueryResult();
|
||||
$result->setLastId(self::$faker->randomNumber());
|
||||
|
||||
$this->publicLinkRepository
|
||||
->expects(self::once())
|
||||
->method('create')
|
||||
->with(
|
||||
new Callback(function (PublicLinkData $actual) use ($publicLinkData) {
|
||||
$filter = ['hash', 'dateExpire', 'maxCountViews', 'data'];
|
||||
|
||||
return $actual->toArray(null, $filter) === $publicLinkData->toArray(null, $filter)
|
||||
&& !empty($actual->getHash())
|
||||
&& !empty($actual->getDateExpire())
|
||||
&& !empty($actual->getMaxCountViews())
|
||||
&& !empty($actual->getData());
|
||||
})
|
||||
)
|
||||
->willReturn($result);
|
||||
|
||||
$passData = ['pass' => self::$faker->password, 'key' => self::$faker->sha1];
|
||||
|
||||
$this->accountService
|
||||
->expects(self::once())
|
||||
->method('getDataForLink')
|
||||
->with($publicLinkData->getItemId())
|
||||
->willReturn(new Simple($passData));
|
||||
|
||||
$this->crypt
|
||||
->expects(self::once())
|
||||
->method('decrypt')
|
||||
->with(
|
||||
$passData['pass'],
|
||||
$passData['key'],
|
||||
$this->context->getTrasientKey(ContextInterface::MASTER_PASSWORD_KEY)
|
||||
)
|
||||
->willReturn(self::$faker->password);
|
||||
|
||||
$actual = $this->publicLinkService->create($publicLinkData);
|
||||
|
||||
$this->assertEquals($result->getLastId(), $actual);
|
||||
}
|
||||
|
||||
public function testCalcDateExpire()
|
||||
{
|
||||
$expireDate = time() + $this->config->getConfigData()->getPublinksMaxTime();
|
||||
|
||||
$this->assertEqualsWithDelta($expireDate, PublicLinkService::calcDateExpire($this->config), 2);
|
||||
}
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->publicLinkRepository = $this->createMock(PublicLinkRepositoryInterface::class);
|
||||
$this->request = $this->createMock(RequestInterface::class);
|
||||
$this->request->method('getClientAddress')
|
||||
->willReturn(self::$faker->ipv4);
|
||||
$this->request->method('getHeader')
|
||||
->willReturn(self::$faker->userAgent);
|
||||
$this->request->method('isHttps')
|
||||
->willReturn(self::$faker->boolean);
|
||||
|
||||
$this->accountService = $this->createMock(AccountServiceInterface::class);
|
||||
$this->crypt = $this->createMock(CryptInterface::class);
|
||||
|
||||
$this->publicLinkService =
|
||||
new PublicLinkService(
|
||||
$this->application,
|
||||
$this->publicLinkRepository,
|
||||
$this->request,
|
||||
$this->accountService,
|
||||
$this->crypt
|
||||
);
|
||||
}
|
||||
}
|
||||
85
tests/SP/Generators/PublicLinkDataGenerator.php
Normal file
85
tests/SP/Generators/PublicLinkDataGenerator.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/*
|
||||
* sysPass
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link https://syspass.org
|
||||
* @copyright 2012-2023, 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\Tests\Generators;
|
||||
|
||||
use SP\DataModel\PublicLinkData;
|
||||
use SP\DataModel\PublicLinkListData;
|
||||
|
||||
/**
|
||||
* Class PublicLinkDataGenerator
|
||||
*/
|
||||
final class PublicLinkDataGenerator extends DataGenerator
|
||||
{
|
||||
public function buildPublicLink(): PublicLinkData
|
||||
{
|
||||
return new PublicLinkData($this->getPublicLinkProperties());
|
||||
}
|
||||
|
||||
private function getPublicLinkProperties(): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->faker->randomNumber(),
|
||||
'itemId' => $this->faker->randomNumber(),
|
||||
'hash' => $this->faker->randomNumber(),
|
||||
'userId' => $this->faker->randomNumber(),
|
||||
'typeId' => $this->faker->randomNumber(),
|
||||
'notify' => $this->faker->boolean,
|
||||
'dateAdd' => $this->faker->unixTime(),
|
||||
'dateUpdate' => $this->faker->unixTime(),
|
||||
'dateExpire' => $this->faker->unixTime(),
|
||||
'countViews' => $this->faker->randomNumber(),
|
||||
'totalCountViews' => $this->faker->randomNumber(),
|
||||
'maxCountViews' => $this->faker->randomNumber(),
|
||||
'useInfo' => serialize($this->getUseInfo()),
|
||||
'data' => $this->faker->text,
|
||||
];
|
||||
}
|
||||
|
||||
private function getUseInfo(): array
|
||||
{
|
||||
return array_map(
|
||||
fn() => [
|
||||
'who' => $this->faker->ipv4,
|
||||
'time' => $this->faker->unixTime,
|
||||
'hash' => $this->faker->sha1,
|
||||
'agent' => $this->faker->userAgent,
|
||||
'https' => $this->faker->boolean,
|
||||
],
|
||||
range(0, 9)
|
||||
);
|
||||
}
|
||||
|
||||
public function buildPublicLinkList(): PublicLinkListData
|
||||
{
|
||||
return new PublicLinkListData(
|
||||
array_merge($this->getPublicLinkProperties(), [
|
||||
'userName' => $this->faker->name,
|
||||
'userLogin' => $this->faker->userName,
|
||||
'accountName' => $this->faker->colorName,
|
||||
'clientName' => $this->faker->company,
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* @author nuxsmin
|
||||
* @link https://syspass.org
|
||||
* @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org
|
||||
* @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org
|
||||
*
|
||||
* This file is part of sysPass.
|
||||
*
|
||||
@@ -86,6 +86,7 @@ abstract class UnitaryTestCase extends TestCase
|
||||
$this->context->initialize();
|
||||
$this->context->setUserData($userLogin);
|
||||
$this->context->setUserProfile(new ProfileData());
|
||||
$this->context->setTrasientKey(ContextInterface::MASTER_PASSWORD_KEY, self::$faker->password);
|
||||
|
||||
$configData = ConfigDataGenerator::factory()->buildConfigData();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user