mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-10 11:33:17 +00:00
Add token entities
This commit is contained in:
@@ -72,6 +72,7 @@ use Alchemy\Phrasea\Controller\Utils\ConnectionTest;
|
|||||||
use Alchemy\Phrasea\Controller\Utils\PathFileTest;
|
use Alchemy\Phrasea\Controller\Utils\PathFileTest;
|
||||||
use Alchemy\Phrasea\Controller\User\Notifications;
|
use Alchemy\Phrasea\Controller\User\Notifications;
|
||||||
use Alchemy\Phrasea\Controller\User\Preferences;
|
use Alchemy\Phrasea\Controller\User\Preferences;
|
||||||
|
use Alchemy\Phrasea\Core\Middleware\TokenMiddlewareProvider;
|
||||||
use Alchemy\Phrasea\Core\PhraseaExceptionHandler;
|
use Alchemy\Phrasea\Core\PhraseaExceptionHandler;
|
||||||
use Alchemy\Phrasea\Core\Event\Subscriber\LogoutSubscriber;
|
use Alchemy\Phrasea\Core\Event\Subscriber\LogoutSubscriber;
|
||||||
use Alchemy\Phrasea\Core\Event\Subscriber\PhraseaLocaleSubscriber;
|
use Alchemy\Phrasea\Core\Event\Subscriber\PhraseaLocaleSubscriber;
|
||||||
@@ -211,6 +212,7 @@ class Application extends SilexApplication
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->register(new BasketMiddlewareProvider());
|
$this->register(new BasketMiddlewareProvider());
|
||||||
|
$this->register(new TokenMiddlewareProvider());
|
||||||
|
|
||||||
$this->register(new ACLServiceProvider());
|
$this->register(new ACLServiceProvider());
|
||||||
$this->register(new AuthenticationManagerServiceProvider());
|
$this->register(new AuthenticationManagerServiceProvider());
|
||||||
|
@@ -1,43 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of Phraseanet
|
|
||||||
*
|
|
||||||
* (c) 2005-2014 Alchemy
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Alchemy\Phrasea\Authentication\Token;
|
|
||||||
|
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|
||||||
|
|
||||||
class TokenValidator
|
|
||||||
{
|
|
||||||
private $random;
|
|
||||||
|
|
||||||
public function __construct(\random $random)
|
|
||||||
{
|
|
||||||
$this->random = $random;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the token is valid
|
|
||||||
*
|
|
||||||
* @param type $token
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function isValid($token)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$datas = $this->random->helloToken($token);
|
|
||||||
|
|
||||||
return $datas['usr_id'];
|
|
||||||
} catch (NotFoundHttpException $e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -26,6 +26,7 @@ use Alchemy\Phrasea\Model\Entities\LazaretSession;
|
|||||||
use Alchemy\Phrasea\Model\Entities\Registration;
|
use Alchemy\Phrasea\Model\Entities\Registration;
|
||||||
use Alchemy\Phrasea\Model\Entities\Session;
|
use Alchemy\Phrasea\Model\Entities\Session;
|
||||||
use Alchemy\Phrasea\Model\Entities\Task;
|
use Alchemy\Phrasea\Model\Entities\Task;
|
||||||
|
use Alchemy\Phrasea\Model\Entities\Token;
|
||||||
use Alchemy\Phrasea\Model\Entities\User;
|
use Alchemy\Phrasea\Model\Entities\User;
|
||||||
use Alchemy\Phrasea\Model\Entities\ValidationData;
|
use Alchemy\Phrasea\Model\Entities\ValidationData;
|
||||||
use Alchemy\Phrasea\Model\Entities\ValidationSession;
|
use Alchemy\Phrasea\Model\Entities\ValidationSession;
|
||||||
@@ -35,6 +36,7 @@ use Alchemy\Phrasea\Model\Entities\UsrList;
|
|||||||
use Alchemy\Phrasea\Model\Entities\UsrListEntry;
|
use Alchemy\Phrasea\Model\Entities\UsrListEntry;
|
||||||
use Alchemy\Phrasea\Model\Entities\StoryWZ;
|
use Alchemy\Phrasea\Model\Entities\StoryWZ;
|
||||||
use Alchemy\Phrasea\Core\Provider\ORMServiceProvider;
|
use Alchemy\Phrasea\Core\Provider\ORMServiceProvider;
|
||||||
|
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||||
use Doctrine\ORM\EntityManager;
|
use Doctrine\ORM\EntityManager;
|
||||||
use Doctrine\ORM\Tools\SchemaTool;
|
use Doctrine\ORM\Tools\SchemaTool;
|
||||||
use Gedmo\Timestampable\TimestampableListener;
|
use Gedmo\Timestampable\TimestampableListener;
|
||||||
@@ -88,6 +90,8 @@ class RegenerateSqliteDb extends Command
|
|||||||
$this->insertOauthApps($DI);
|
$this->insertOauthApps($DI);
|
||||||
$this->generateCollection($DI);
|
$this->generateCollection($DI);
|
||||||
$this->generateRecord($DI);
|
$this->generateRecord($DI);
|
||||||
|
$this->insertTwoTasks($this->container['EM']);
|
||||||
|
$this->insertTwoBasket($this->container['EM'], $DI);
|
||||||
$this->insertOneStoryInWz($this->container['EM'], $DI);
|
$this->insertOneStoryInWz($this->container['EM'], $DI);
|
||||||
$this->insertUsrLists($this->container['EM'], $DI);
|
$this->insertUsrLists($this->container['EM'], $DI);
|
||||||
$this->insertOnePrivateFeed($this->container['EM'], $DI);
|
$this->insertOnePrivateFeed($this->container['EM'], $DI);
|
||||||
@@ -99,7 +103,21 @@ class RegenerateSqliteDb extends Command
|
|||||||
$this->insertOneRegistration($DI, $this->container['EM'], $DI['user_alt1'], $DI['coll'], 'now', 'registration_1');
|
$this->insertOneRegistration($DI, $this->container['EM'], $DI['user_alt1'], $DI['coll'], 'now', 'registration_1');
|
||||||
$this->insertOneRegistration($DI, $this->container['EM'], $DI['user_alt2'], $DI['coll'], '-3 months', 'registration_2');
|
$this->insertOneRegistration($DI, $this->container['EM'], $DI['user_alt2'], $DI['coll'], '-3 months', 'registration_2');
|
||||||
$this->insertOneRegistration($DI, $this->container['EM'], $DI['user_notAdmin'], $DI['coll'], 'now', 'registration_3');
|
$this->insertOneRegistration($DI, $this->container['EM'], $DI['user_notAdmin'], $DI['coll'], 'now', 'registration_3');
|
||||||
|
$this->insertTwoTokens($this->container['EM'], $DI);
|
||||||
|
$this->insertOneInvalidToken($this->container['EM'], $DI);
|
||||||
|
$this->insertOneValidationToken($this->container['EM'], $DI);
|
||||||
|
|
||||||
|
$this->container['EM']->flush();
|
||||||
|
|
||||||
|
$fixtures['basket']['basket_1'] = $DI['basket_1']->getId();
|
||||||
|
$fixtures['basket']['basket_2'] = $DI['basket_2']->getId();
|
||||||
|
$fixtures['basket']['basket_3'] = $DI['basket_3']->getId();
|
||||||
|
$fixtures['basket']['basket_4'] = $DI['basket_4']->getId();
|
||||||
|
|
||||||
|
$fixtures['token']['token_1'] = $DI['token_1']->getValue();
|
||||||
|
$fixtures['token']['token_2'] = $DI['token_2']->getValue();
|
||||||
|
$fixtures['token']['token_invalid'] = $DI['token_invalid']->getValue();
|
||||||
|
$fixtures['token']['token_validation'] = $DI['token_validation']->getValue();
|
||||||
$fixtures['user']['test_phpunit'] = $DI['user']->getId();
|
$fixtures['user']['test_phpunit'] = $DI['user']->getId();
|
||||||
$fixtures['user']['test_phpunit_not_admin'] = $DI['user_notAdmin']->getId();
|
$fixtures['user']['test_phpunit_not_admin'] = $DI['user_notAdmin']->getId();
|
||||||
$fixtures['user']['test_phpunit_alt1'] = $DI['user_alt1']->getId();
|
$fixtures['user']['test_phpunit_alt1'] = $DI['user_alt1']->getId();
|
||||||
@@ -140,10 +158,13 @@ class RegenerateSqliteDb extends Command
|
|||||||
$fixtures['user']['user_3_deleted'] = $DI['user_3_deleted']->getId();
|
$fixtures['user']['user_3_deleted'] = $DI['user_3_deleted']->getId();
|
||||||
$fixtures['user']['user_template'] = $DI['user_template']->getId();
|
$fixtures['user']['user_template'] = $DI['user_template']->getId();
|
||||||
|
|
||||||
$this->insertTwoTasks($this->container['EM']);
|
$fixtures['feed']['public']['feed'] = $DI['feed_public']->getId();
|
||||||
$this->insertTwoBasket($this->container['EM'], $DI);
|
$fixtures['feed']['public']['entry'] = $DI['feed_public_entry']->getId();
|
||||||
|
$fixtures['feed']['public']['token'] = $DI['feed_public_token']->getId();
|
||||||
|
|
||||||
$this->container['EM']->flush();
|
$fixtures['feed']['private']['feed'] = $DI['feed_private']->getId();
|
||||||
|
$fixtures['feed']['private']['entry'] = $DI['feed_private_entry']->getId();
|
||||||
|
$fixtures['feed']['private']['token'] = $DI['feed_private_token']->getId();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$output->writeln("<error>".$e->getMessage()."</error>");
|
$output->writeln("<error>".$e->getMessage()."</error>");
|
||||||
if ($renamed) {
|
if ($renamed) {
|
||||||
@@ -200,7 +221,6 @@ class RegenerateSqliteDb extends Command
|
|||||||
$session = new LazaretSession();
|
$session = new LazaretSession();
|
||||||
$session->setUser($DI['user']);
|
$session->setUser($DI['user']);
|
||||||
$em->persist($session);
|
$em->persist($session);
|
||||||
$em->flush();
|
|
||||||
|
|
||||||
$file = File::buildFromPathfile($this->container['root.path'] . '/tests/files/cestlafete.jpg', $DI['coll'], $this->container);
|
$file = File::buildFromPathfile($this->container['root.path'] . '/tests/files/cestlafete.jpg', $DI['coll'], $this->container);
|
||||||
|
|
||||||
@@ -248,8 +268,6 @@ class RegenerateSqliteDb extends Command
|
|||||||
$em->persist($user2Deleted);
|
$em->persist($user2Deleted);
|
||||||
$em->persist($user3Deleted);
|
$em->persist($user3Deleted);
|
||||||
$em->persist($template);
|
$em->persist($template);
|
||||||
|
|
||||||
$em->flush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function insertOneUser($login, $email = null, $admin = false)
|
protected function insertOneUser($login, $email = null, $admin = false)
|
||||||
@@ -385,6 +403,8 @@ class RegenerateSqliteDb extends Command
|
|||||||
$basket1->setName('test');
|
$basket1->setName('test');
|
||||||
$basket1->setDescription('description test');
|
$basket1->setDescription('description test');
|
||||||
|
|
||||||
|
$DI['basket_1'] = $basket1;
|
||||||
|
|
||||||
$element = new BasketElement();
|
$element = new BasketElement();
|
||||||
$element->setRecord($DI['record_1']);
|
$element->setRecord($DI['record_1']);
|
||||||
$basket1->addElement($element);
|
$basket1->addElement($element);
|
||||||
@@ -395,11 +415,15 @@ class RegenerateSqliteDb extends Command
|
|||||||
$basket2->setName('test');
|
$basket2->setName('test');
|
||||||
$basket2->setDescription('description test');
|
$basket2->setDescription('description test');
|
||||||
|
|
||||||
|
$DI['basket_2'] = $basket2;
|
||||||
|
|
||||||
$basket3 = new Basket();
|
$basket3 = new Basket();
|
||||||
$basket3->setUser($this->getUserAlt1());
|
$basket3->setUser($this->getUserAlt1());
|
||||||
$basket3->setName('test');
|
$basket3->setName('test');
|
||||||
$basket3->setDescription('description test');
|
$basket3->setDescription('description test');
|
||||||
|
|
||||||
|
$DI['basket_3'] = $basket3;
|
||||||
|
|
||||||
$em->persist($basket1);
|
$em->persist($basket1);
|
||||||
$em->persist($element);
|
$em->persist($element);
|
||||||
$em->persist($basket2);
|
$em->persist($basket2);
|
||||||
@@ -442,6 +466,8 @@ class RegenerateSqliteDb extends Command
|
|||||||
$em->persist($validationParticipant);
|
$em->persist($validationParticipant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$DI['basket_4'] = $basket4;
|
||||||
|
|
||||||
$em->persist($basket4);
|
$em->persist($basket4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -524,8 +550,12 @@ class RegenerateSqliteDb extends Command
|
|||||||
$em->persist($feed);
|
$em->persist($feed);
|
||||||
$em->persist($publisher);
|
$em->persist($publisher);
|
||||||
|
|
||||||
$this->insertOneFeedEntry($em, $DI, $feed, true);
|
$entry = $this->insertOneFeedEntry($em, $DI, $feed, true);
|
||||||
$this->insertOneFeedToken($em, $DI, $feed);
|
$token = $this->insertOneFeedToken($em, $DI, $feed);
|
||||||
|
|
||||||
|
$DI['feed_public'] = $feed;
|
||||||
|
$DI['feed_public_entry'] = $entry;
|
||||||
|
$DI['feed_public_token'] = $token;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function insertOnePrivateFeed(EntityManager $em, \Pimple $DI)
|
private function insertOnePrivateFeed(EntityManager $em, \Pimple $DI)
|
||||||
@@ -547,8 +577,12 @@ class RegenerateSqliteDb extends Command
|
|||||||
$em->persist($feed);
|
$em->persist($feed);
|
||||||
$em->persist($publisher);
|
$em->persist($publisher);
|
||||||
|
|
||||||
$this->insertOneFeedEntry($em, $DI, $feed, false);
|
$entry = $this->insertOneFeedEntry($em, $DI, $feed, false);
|
||||||
$this->insertOneFeedToken($em, $DI, $feed);
|
$token = $this->insertOneFeedToken($em, $DI, $feed);
|
||||||
|
|
||||||
|
$DI['feed_private'] = $feed;
|
||||||
|
$DI['feed_private_entry'] = $entry;
|
||||||
|
$DI['feed_private_token'] = $token;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function insertOneExtraFeed(EntityManager $em, \Pimple $DI)
|
private function insertOneExtraFeed(EntityManager $em, \Pimple $DI)
|
||||||
@@ -595,12 +629,14 @@ class RegenerateSqliteDb extends Command
|
|||||||
$em->persist($feed);
|
$em->persist($feed);
|
||||||
|
|
||||||
$this->insertOneFeedItem($em, $DI, $entry, $public);
|
$this->insertOneFeedItem($em, $DI, $entry, $public);
|
||||||
|
|
||||||
|
return $entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function insertOneFeedToken(EntityManager $em, \Pimple $DI, Feed $feed)
|
private function insertOneFeedToken(EntityManager $em, \Pimple $DI, Feed $feed)
|
||||||
{
|
{
|
||||||
$token = new FeedToken();
|
$token = new FeedToken();
|
||||||
$token->setValue($this->container['random.low']->generateString(64, \random::LETTERS_AND_NUMBERS));
|
$token->setValue($this->container['random.low']->generateString(64, TokenManipulator::LETTERS_AND_NUMBERS));
|
||||||
$token->setFeed($feed);
|
$token->setFeed($feed);
|
||||||
$token->setUser($DI['user']);
|
$token->setUser($DI['user']);
|
||||||
|
|
||||||
@@ -608,6 +644,8 @@ class RegenerateSqliteDb extends Command
|
|||||||
|
|
||||||
$em->persist($token);
|
$em->persist($token);
|
||||||
$em->persist($feed);
|
$em->persist($feed);
|
||||||
|
|
||||||
|
return $token;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function insertOneAggregateToken(EntityManager $em, \Pimple $DI)
|
private function insertOneAggregateToken(EntityManager $em, \Pimple $DI)
|
||||||
@@ -615,12 +653,61 @@ class RegenerateSqliteDb extends Command
|
|||||||
$user = $DI['user'];
|
$user = $DI['user'];
|
||||||
|
|
||||||
$token = new AggregateToken();
|
$token = new AggregateToken();
|
||||||
$token->setValue($this->container['random.low']->generateString(64, \random::LETTERS_AND_NUMBERS));
|
$token->setValue($this->container['random.low']->generateString(64, TokenManipulator::LETTERS_AND_NUMBERS));
|
||||||
$token->setUser($user);
|
$token->setUser($user);
|
||||||
|
|
||||||
$em->persist($token);
|
$em->persist($token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function insertTwoTokens(EntityManager $em, \Pimple $DI)
|
||||||
|
{
|
||||||
|
$user = $DI['user'];
|
||||||
|
|
||||||
|
$token = new Token();
|
||||||
|
$token->setValue($this->container['random.low']->generateString(12, TokenManipulator::LETTERS_AND_NUMBERS));
|
||||||
|
$token->setUser($user);
|
||||||
|
$token->setType(TokenManipulator::TYPE_RSS);
|
||||||
|
$token->setData('some data');
|
||||||
|
$DI['token_1'] = $token;
|
||||||
|
$em->persist($token);
|
||||||
|
|
||||||
|
$token = new Token();
|
||||||
|
$token->setValue($this->container['random.low']->generateString(12, TokenManipulator::LETTERS_AND_NUMBERS));
|
||||||
|
$token->setUser($user);
|
||||||
|
$token->setType(TokenManipulator::TYPE_RSS);
|
||||||
|
$token->setData('some data');
|
||||||
|
$token->setExpiration(new \DateTime('+1 year'));
|
||||||
|
$DI['token_2'] = $token;
|
||||||
|
$em->persist($token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function insertOneInvalidToken(EntityManager $em, \Pimple $DI)
|
||||||
|
{
|
||||||
|
$user = $DI['user'];
|
||||||
|
|
||||||
|
$token = new Token();
|
||||||
|
$token->setValue($this->container['random.low']->generateString(12, TokenManipulator::LETTERS_AND_NUMBERS));
|
||||||
|
$token->setUser($user);
|
||||||
|
$token->setType(TokenManipulator::TYPE_RSS);
|
||||||
|
$token->setData('some data');
|
||||||
|
$token->setExpiration(new \DateTime('-1 day'));
|
||||||
|
$DI['token_invalid'] = $token;
|
||||||
|
$em->persist($token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function insertOneValidationToken(EntityManager $em, \Pimple $DI)
|
||||||
|
{
|
||||||
|
$user = $DI['user'];
|
||||||
|
|
||||||
|
$token = new Token();
|
||||||
|
$token->setValue($this->container['random.low']->generateString(12, TokenManipulator::LETTERS_AND_NUMBERS));
|
||||||
|
$token->setUser($user);
|
||||||
|
$token->setType(TokenManipulator::TYPE_VALIDATE);
|
||||||
|
$token->setData($DI['basket_1']->getId());
|
||||||
|
$DI['token_validation'] = $token;
|
||||||
|
$em->persist($token);
|
||||||
|
}
|
||||||
|
|
||||||
private function insertOneFeedItem(EntityManager $em, \Pimple $DI, FeedEntry $entry, $public)
|
private function insertOneFeedItem(EntityManager $em, \Pimple $DI, FeedEntry $entry, $public)
|
||||||
{
|
{
|
||||||
if ($public) {
|
if ($public) {
|
||||||
@@ -656,7 +743,6 @@ class RegenerateSqliteDb extends Command
|
|||||||
$registration->setUpdated(new \DateTime($when));
|
$registration->setUpdated(new \DateTime($when));
|
||||||
$registration->setCreated(new \DateTime($when));
|
$registration->setCreated(new \DateTime($when));
|
||||||
$em->persist($registration);
|
$em->persist($registration);
|
||||||
$em->flush();
|
|
||||||
$em->getEventManager()->addEventSubscriber(new TimestampableListener());
|
$em->getEventManager()->addEventSubscriber(new TimestampableListener());
|
||||||
|
|
||||||
$DI[$name] = $registration;
|
$DI[$name] = $registration;
|
||||||
|
@@ -15,6 +15,7 @@ use Alchemy\Phrasea\Model\Entities\Basket;
|
|||||||
use Alchemy\Phrasea\Model\Entities\BasketElement;
|
use Alchemy\Phrasea\Model\Entities\BasketElement;
|
||||||
use Alchemy\Phrasea\Exception\SessionNotFound;
|
use Alchemy\Phrasea\Exception\SessionNotFound;
|
||||||
use Alchemy\Phrasea\Controller\Exception as ControllerException;
|
use Alchemy\Phrasea\Controller\Exception as ControllerException;
|
||||||
|
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||||
use Silex\ControllerProviderInterface;
|
use Silex\ControllerProviderInterface;
|
||||||
use Silex\Application as SilexApplication;
|
use Silex\Application as SilexApplication;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
@@ -38,26 +39,21 @@ class Lightbox implements ControllerProviderInterface
|
|||||||
$app['authentication']->closeAccount();
|
$app['authentication']->closeAccount();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (false === $usr_id = $app['authentication.token-validator']->isValid($request->query->get('LOG'))) {
|
if (null === $token = $app['repo.tokens']->findValidToken($request->query->get('LOG'))) {
|
||||||
$app->addFlash('error', $app->trans('The URL you used is out of date, please login'));
|
$app->addFlash('error', $app->trans('The URL you used is out of date, please login'));
|
||||||
|
|
||||||
return $app->redirectPath('homepage');
|
return $app->redirectPath('homepage');
|
||||||
}
|
}
|
||||||
|
|
||||||
$app['authentication']->openAccount($app['repo.users']->find($usr_id));
|
$app['authentication']->openAccount($token->getUser());
|
||||||
|
|
||||||
try {
|
switch ($token->getType()) {
|
||||||
$datas = $app['tokens']->helloToken($request->query->get('LOG'));
|
case TokenManipulator::TYPE_FEED_ENTRY:
|
||||||
} catch (NotFoundHttpException $e) {
|
return $app->redirectPath('lightbox_feed_entry', ['entry_id' => $token->getData()]);
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch ($datas['type']) {
|
|
||||||
case \random::TYPE_FEED_ENTRY:
|
|
||||||
return $app->redirectPath('lightbox_feed_entry', ['entry_id' => $datas['datas']]);
|
|
||||||
break;
|
break;
|
||||||
case \random::TYPE_VALIDATE:
|
case TokenManipulator::TYPE_VALIDATE:
|
||||||
case \random::TYPE_VIEW:
|
case TokenManipulator::TYPE_VIEW:
|
||||||
return $app->redirectPath('lightbox_validation', ['basket' => $datas['datas']]);
|
return $app->redirectPath('lightbox_validation', ['basket' => $token->getData()]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -464,13 +460,8 @@ class Lightbox implements ControllerProviderInterface
|
|||||||
/* @var $basket Basket */
|
/* @var $basket Basket */
|
||||||
$participant = $basket->getValidation()->getParticipant($app['authentication']->getUser());
|
$participant = $basket->getValidation()->getParticipant($app['authentication']->getUser());
|
||||||
|
|
||||||
$expires = new \DateTime('+10 days');
|
$token = $app['manipulator.token']->createBasketValidationToken($basket);
|
||||||
$url = $app->url('lightbox', ['LOG' => $app['tokens']->getUrlToken(
|
$url = $app->url('lightbox', ['LOG' => $token->getValue()]);
|
||||||
\random::TYPE_VALIDATE
|
|
||||||
, $basket->getValidation()->getInitiator($app)->getId()
|
|
||||||
, $expires
|
|
||||||
, $basket->getId()
|
|
||||||
)]);
|
|
||||||
|
|
||||||
$to = $basket->getValidation()->getInitiator($app)->getId();
|
$to = $basket->getValidation()->getInitiator($app)->getId();
|
||||||
$params = [
|
$params = [
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
namespace Alchemy\Phrasea\Controller\Prod;
|
namespace Alchemy\Phrasea\Controller\Prod;
|
||||||
|
|
||||||
use Alchemy\Phrasea\Http\DeliverDataInterface;
|
use Alchemy\Phrasea\Http\DeliverDataInterface;
|
||||||
|
use Alchemy\Phrasea\Model\Entities\Token;
|
||||||
use Silex\Application;
|
use Silex\Application;
|
||||||
use Silex\ControllerProviderInterface;
|
use Silex\ControllerProviderInterface;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
@@ -32,16 +33,19 @@ class DoDownload implements ControllerProviderInterface
|
|||||||
$controllers = $app['controllers_factory'];
|
$controllers = $app['controllers_factory'];
|
||||||
|
|
||||||
$controllers->get('/{token}/prepare/', 'controller.prod.do-download:prepareDownload')
|
$controllers->get('/{token}/prepare/', 'controller.prod.do-download:prepareDownload')
|
||||||
|
->before($app['middleware.token.converter'])
|
||||||
->bind('prepare_download')
|
->bind('prepare_download')
|
||||||
->assert('token', '[a-zA-Z0-9\.\/]{8,16}');
|
->assert('token', '[a-zA-Z0-9]{8,32}');
|
||||||
|
|
||||||
$controllers->match('/{token}/get/', 'controller.prod.do-download:downloadDocuments')
|
$controllers->match('/{token}/get/', 'controller.prod.do-download:downloadDocuments')
|
||||||
|
->before($app['middleware.token.converter'])
|
||||||
->bind('document_download')
|
->bind('document_download')
|
||||||
->assert('token', '[a-zA-Z0-9\.\/]{8,16}');
|
->assert('token', '[a-zA-Z0-9]{8,32}');
|
||||||
|
|
||||||
$controllers->post('/{token}/execute/', 'controller.prod.do-download:downloadExecute')
|
$controllers->post('/{token}/execute/', 'controller.prod.do-download:downloadExecute')
|
||||||
|
->before($app['middleware.token.converter'])
|
||||||
->bind('execute_download')
|
->bind('execute_download')
|
||||||
->assert('token', '[a-zA-Z0-9\.\/]{8,16}');
|
->assert('token', '[a-zA-Z0-9]{8,32}');
|
||||||
|
|
||||||
return $controllers;
|
return $controllers;
|
||||||
}
|
}
|
||||||
@@ -51,15 +55,13 @@ class DoDownload implements ControllerProviderInterface
|
|||||||
*
|
*
|
||||||
* @param Application $app
|
* @param Application $app
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param String $token
|
* @param Token $token
|
||||||
*
|
*
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
public function prepareDownload(Application $app, Request $request, $token)
|
public function prepareDownload(Application $app, Request $request, Token $token)
|
||||||
{
|
{
|
||||||
$datas = $app['tokens']->helloToken($token);
|
if (false === $list = @unserialize($token->getData())) {
|
||||||
|
|
||||||
if (false === $list = @unserialize((string) $datas['datas'])) {
|
|
||||||
$app->abort(500, 'Invalid datas');
|
$app->abort(500, 'Invalid datas');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,15 +98,13 @@ class DoDownload implements ControllerProviderInterface
|
|||||||
*
|
*
|
||||||
* @param Application $app
|
* @param Application $app
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param String $token
|
* @param Token $token
|
||||||
*
|
*
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
public function downloadDocuments(Application $app, Request $request, $token)
|
public function downloadDocuments(Application $app, Request $request, Token $token)
|
||||||
{
|
{
|
||||||
$datas = $app['tokens']->helloToken($token);
|
if (false === $list = @unserialize($token->getData())) {
|
||||||
|
|
||||||
if (false === $list = @unserialize((string) $datas['datas'])) {
|
|
||||||
$app->abort(500, 'Invalid datas');
|
$app->abort(500, 'Invalid datas');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ class DoDownload implements ControllerProviderInterface
|
|||||||
$mime = $subdef['mime'];
|
$mime = $subdef['mime'];
|
||||||
$list['complete'] = true;
|
$list['complete'] = true;
|
||||||
} else {
|
} else {
|
||||||
$exportFile = $app['root.path'] . '/tmp/download/' . $datas['value'] . '.zip';
|
$exportFile = $app['root.path'] . '/tmp/download/' . $token->getValue() . '.zip';
|
||||||
$mime = 'application/zip';
|
$mime = 'application/zip';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,22 +144,13 @@ class DoDownload implements ControllerProviderInterface
|
|||||||
*
|
*
|
||||||
* @param Application $app
|
* @param Application $app
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param String $token
|
* @param Token $token
|
||||||
*
|
*
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
public function downloadExecute(Application $app, Request $request, $token)
|
public function downloadExecute(Application $app, Request $request, Token $token)
|
||||||
{
|
{
|
||||||
try {
|
if (false === $list = @unserialize($token->getData())) {
|
||||||
$datas = $app['tokens']->helloToken($token);
|
|
||||||
} catch (NotFoundHttpException $e) {
|
|
||||||
return $app->json([
|
|
||||||
'success' => false,
|
|
||||||
'message' => 'Invalid token'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false === $list = @unserialize((string) $datas['datas'])) {
|
|
||||||
return $app->json([
|
return $app->json([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
'message' => 'Invalid datas'
|
'message' => 'Invalid datas'
|
||||||
@@ -175,7 +166,7 @@ class DoDownload implements ControllerProviderInterface
|
|||||||
$app,
|
$app,
|
||||||
$token,
|
$token,
|
||||||
$list,
|
$list,
|
||||||
sprintf($app['root.path'] . '/tmp/download/%s.zip', $datas['value']) // Dest file
|
sprintf($app['root.path'] . '/tmp/download/%s.zip', $token->getValue()) // Dest file
|
||||||
);
|
);
|
||||||
|
|
||||||
return $app->json([
|
return $app->json([
|
||||||
|
@@ -64,16 +64,7 @@ class Download implements ControllerProviderInterface
|
|||||||
|
|
||||||
$list['export_name'] = sprintf('%s.zip', $download->getExportName());
|
$list['export_name'] = sprintf('%s.zip', $download->getExportName());
|
||||||
|
|
||||||
$token = $app['tokens']->getUrlToken(
|
$token = $app['manipulator.token']->createDownloadToken($app['authentication']->getUser(), serialize($list));
|
||||||
\random::TYPE_DOWNLOAD,
|
|
||||||
$app['authentication']->getUser()->getId(),
|
|
||||||
new \DateTime('+3 hours'), // Token lifetime
|
|
||||||
serialize($list)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!$token) {
|
|
||||||
throw new \RuntimeException('Download token could not be generated');
|
|
||||||
}
|
|
||||||
|
|
||||||
$app['events-manager']->trigger('__DOWNLOAD__', [
|
$app['events-manager']->trigger('__DOWNLOAD__', [
|
||||||
'lst' => $lst,
|
'lst' => $lst,
|
||||||
@@ -83,6 +74,6 @@ class Download implements ControllerProviderInterface
|
|||||||
'export_file' => $download->getExportName()
|
'export_file' => $download->getExportName()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $app->redirectPath('prepare_download', ['token' => $token]);
|
return $app->redirectPath('prepare_download', ['token' => $token->getValue()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -215,22 +215,20 @@ class Export implements ControllerProviderInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//generate validation token
|
$token = $app['manipulator.token']->createEmailExportToken(serialize($list));
|
||||||
$endDateObject = new \DateTime('+1 day');
|
|
||||||
$token = $app['tokens']->getUrlToken(\random::TYPE_EMAIL, false, $endDateObject, serialize($list));
|
|
||||||
|
|
||||||
if (count($destMails) > 0 && $token) {
|
if (count($destMails) > 0) {
|
||||||
//zip documents
|
//zip documents
|
||||||
\set_export::build_zip(
|
\set_export::build_zip(
|
||||||
$app,
|
$app,
|
||||||
$token,
|
$token,
|
||||||
$list,
|
$list,
|
||||||
$app['root.path'] . '/tmp/download/' . $token . '.zip'
|
$app['root.path'] . '/tmp/download/' . $token->getValue() . '.zip'
|
||||||
);
|
);
|
||||||
|
|
||||||
$remaingEmails = $destMails;
|
$remaingEmails = $destMails;
|
||||||
|
|
||||||
$url = $app->url('prepare_download', ['token' => $token, 'anonymous']);
|
$url = $app->url('prepare_download', ['token' => $token->getValue(), 'anonymous']);
|
||||||
|
|
||||||
$emitter = new Emitter($app['authentication']->getUser()->getDisplayName(), $app['authentication']->getUser()->getEmail());
|
$emitter = new Emitter($app['authentication']->getUser()->getDisplayName(), $app['authentication']->getUser()->getEmail());
|
||||||
|
|
||||||
@@ -243,7 +241,7 @@ class Export implements ControllerProviderInterface
|
|||||||
|
|
||||||
$mail = MailRecordsExport::create($app, $receiver, $emitter, $request->request->get('textmail'));
|
$mail = MailRecordsExport::create($app, $receiver, $emitter, $request->request->get('textmail'));
|
||||||
$mail->setButtonUrl($url);
|
$mail->setButtonUrl($url);
|
||||||
$mail->setExpiration($endDateObject);
|
$mail->setExpiration($token->getExpiration());
|
||||||
|
|
||||||
$app['notification.deliverer']->deliver($mail);
|
$app['notification.deliverer']->deliver($mail);
|
||||||
unset($remaingEmails[$key]);
|
unset($remaingEmails[$key]);
|
||||||
@@ -261,16 +259,6 @@ class Export implements ControllerProviderInterface
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif (!$token && count($destMails) > 0) { //couldn't generate token
|
|
||||||
foreach ($destMails as $mail) {
|
|
||||||
$app['events-manager']->trigger('__EXPORT_MAIL_FAIL__', [
|
|
||||||
'usr_id' => $app['authentication']->getUser()->getId(),
|
|
||||||
'lst' => $lst,
|
|
||||||
'ssttid' => $ssttid,
|
|
||||||
'dest' => $mail,
|
|
||||||
'reason' => 0
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $app->json([
|
return $app->json([
|
||||||
|
@@ -219,12 +219,7 @@ class Push implements ControllerProviderInterface
|
|||||||
|
|
||||||
$url = $app->url('lightbox_compare', [
|
$url = $app->url('lightbox_compare', [
|
||||||
'basket' => $Basket->getId(),
|
'basket' => $Basket->getId(),
|
||||||
'LOG' => $app['tokens']->getUrlToken(
|
'LOG' => $app['manipulator.token']->createBasketAccessToken($Basket, $user_receiver),
|
||||||
\random::TYPE_VIEW,
|
|
||||||
$user_receiver->getId(),
|
|
||||||
null,
|
|
||||||
$Basket->getId()
|
|
||||||
)
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$receipt = $request->get('recept') ? $app['authentication']->getUser()->getEmail() : '';
|
$receipt = $request->get('recept') ? $app['authentication']->getUser()->getEmail() : '';
|
||||||
@@ -414,12 +409,7 @@ class Push implements ControllerProviderInterface
|
|||||||
|
|
||||||
$url = $app->url('lightbox_validation', [
|
$url = $app->url('lightbox_validation', [
|
||||||
'basket' => $Basket->getId(),
|
'basket' => $Basket->getId(),
|
||||||
'LOG' => $app['tokens']->getUrlToken(
|
'LOG' => $app['manipulator.token']->createBasketValidationToken($Basket, $participant_user),
|
||||||
\random::TYPE_VALIDATE,
|
|
||||||
$participant_user->getId(),
|
|
||||||
null,
|
|
||||||
$Basket->getId()
|
|
||||||
)
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$receipt = $request->get('recept') ? $app['authentication']->getUser()->getEmail() : '';
|
$receipt = $request->get('recept') ? $app['authentication']->getUser()->getEmail() : '';
|
||||||
|
@@ -138,9 +138,8 @@ class Account implements ControllerProviderInterface
|
|||||||
return $app->redirectPath('account_reset_email');
|
return $app->redirectPath('account_reset_email');
|
||||||
}
|
}
|
||||||
|
|
||||||
$date = new \DateTime('1 day');
|
$token = $app['manipulator.token']->createResetEmailToken($app['authentication']->getUser(), $email);
|
||||||
$token = $app['tokens']->getUrlToken(\random::TYPE_EMAIL, $app['authentication']->getUser()->getId(), $date, $app['authentication']->getUser()->getEmail());
|
$url = $app->url('account_reset_email', ['token' => $token->getValue()]);
|
||||||
$url = $app->url('account_reset_email', ['token' => $token]);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$receiver = Receiver::fromUser($app['authentication']->getUser());
|
$receiver = Receiver::fromUser($app['authentication']->getUser());
|
||||||
@@ -152,7 +151,7 @@ class Account implements ControllerProviderInterface
|
|||||||
|
|
||||||
$mail = MailRequestEmailUpdate::create($app, $receiver, null);
|
$mail = MailRequestEmailUpdate::create($app, $receiver, null);
|
||||||
$mail->setButtonUrl($url);
|
$mail->setButtonUrl($url);
|
||||||
$mail->setExpiration($date);
|
$mail->setExpiration($token->getExpiration());
|
||||||
|
|
||||||
$app['notification.deliverer']->deliver($mail);
|
$app['notification.deliverer']->deliver($mail);
|
||||||
|
|
||||||
@@ -170,21 +169,20 @@ class Account implements ControllerProviderInterface
|
|||||||
*/
|
*/
|
||||||
public function displayResetEmailForm(Application $app, Request $request)
|
public function displayResetEmailForm(Application $app, Request $request)
|
||||||
{
|
{
|
||||||
if (null !== $token = $request->query->get('token')) {
|
if (null !== $tokenValue = $request->query->get('token')) {
|
||||||
try {
|
if (null === $token = $app['repo.tokens']->findValidToken($tokenValue)) {
|
||||||
$datas = $app['tokens']->helloToken($token);
|
|
||||||
$user = $app['repo.users']->find((int) $datas['usr_id']);
|
|
||||||
$user->setEmail($datas['datas']);
|
|
||||||
$app['tokens']->removeToken($token);
|
|
||||||
|
|
||||||
$app->addFlash('success', $app->trans('admin::compte-utilisateur: L\'email a correctement ete mis a jour'));
|
|
||||||
|
|
||||||
return $app->redirectPath('account');
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$app->addFlash('error', $app->trans('admin::compte-utilisateur: erreur lors de la mise a jour'));
|
$app->addFlash('error', $app->trans('admin::compte-utilisateur: erreur lors de la mise a jour'));
|
||||||
|
|
||||||
return $app->redirectPath('account');
|
return $app->redirectPath('account');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$user = $token->getUser();
|
||||||
|
$user->setEmail($token->getData());
|
||||||
|
$app['manipulator.token']->delete($token);
|
||||||
|
|
||||||
|
$app->addFlash('success', $app->trans('admin::compte-utilisateur: L\'email a correctement ete mis a jour'));
|
||||||
|
|
||||||
|
return $app->redirectPath('account');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $app['twig']->render('account/reset-email.html.twig', Login::getDefaultTemplateVariables($app));
|
return $app['twig']->render('account/reset-email.html.twig', Login::getDefaultTemplateVariables($app));
|
||||||
|
@@ -505,12 +505,11 @@ class Login implements ControllerProviderInterface
|
|||||||
{
|
{
|
||||||
$receiver = Receiver::fromUser($user);
|
$receiver = Receiver::fromUser($user);
|
||||||
|
|
||||||
$expire = new \DateTime('+3 days');
|
$token = $app['manipulator.token']->createAccountUnlockToken($user);
|
||||||
$token = $app['tokens']->getUrlToken(\random::TYPE_PASSWORD, $user->getId(), $expire, $user->getEmail());
|
|
||||||
|
|
||||||
$mail = MailRequestEmailConfirmation::create($app, $receiver);
|
$mail = MailRequestEmailConfirmation::create($app, $receiver);
|
||||||
$mail->setButtonUrl($app->url('login_register_confirm', ['code' => $token]));
|
$mail->setButtonUrl($app->url('login_register_confirm', ['code' => $token->getValue()]));
|
||||||
$mail->setExpiration($expire);
|
$mail->setExpiration($token->getExpiration());
|
||||||
|
|
||||||
$app['notification.deliverer']->deliver($mail);
|
$app['notification.deliverer']->deliver($mail);
|
||||||
}
|
}
|
||||||
@@ -530,19 +529,13 @@ class Login implements ControllerProviderInterface
|
|||||||
return $app->redirectPath('homepage');
|
return $app->redirectPath('homepage');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (null === $token = $app['repo.tokens']->findValidToken($code)) {
|
||||||
$datas = $app['tokens']->helloToken($code);
|
|
||||||
} catch (NotFoundHttpException $e) {
|
|
||||||
$app->addFlash('error', $app->trans('Invalid unlock link.'));
|
$app->addFlash('error', $app->trans('Invalid unlock link.'));
|
||||||
|
|
||||||
return $app->redirectPath('homepage');
|
return $app->redirectPath('homepage');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $user = $app['repo.users']->find((int) $datas['usr_id'])) {
|
$user = $token->getUser();
|
||||||
$app->addFlash('error', _('Invalid unlock link.'));
|
|
||||||
|
|
||||||
return $app->redirectPath('homepage');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$user->isMailLocked()) {
|
if (!$user->isMailLocked()) {
|
||||||
$app->addFlash('info', $app->trans('Account is already unlocked, you can login.'));
|
$app->addFlash('info', $app->trans('Account is already unlocked, you can login.'));
|
||||||
@@ -550,7 +543,7 @@ class Login implements ControllerProviderInterface
|
|||||||
return $app->redirectPath('homepage');
|
return $app->redirectPath('homepage');
|
||||||
}
|
}
|
||||||
|
|
||||||
$app['tokens']->removeToken($code);
|
$app['manipulator.token']->delete($token);
|
||||||
$user->setMailLocked(false);
|
$user->setMailLocked(false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -561,7 +554,7 @@ class Login implements ControllerProviderInterface
|
|||||||
return $app->redirectPath('homepage');
|
return $app->redirectPath('homepage');
|
||||||
}
|
}
|
||||||
|
|
||||||
$app['tokens']->removeToken($code);
|
$app['manipulator.token']->delete($token);
|
||||||
|
|
||||||
if (count($app['acl']->get($user)->get_granted_base()) > 0) {
|
if (count($app['acl']->get($user)->get_granted_base()) > 0) {
|
||||||
$mail = MailSuccessEmailConfirmationRegistered::create($app, $receiver);
|
$mail = MailSuccessEmailConfirmationRegistered::create($app, $receiver);
|
||||||
@@ -580,39 +573,27 @@ class Login implements ControllerProviderInterface
|
|||||||
|
|
||||||
public function renewPassword(PhraseaApplication $app, Request $request)
|
public function renewPassword(PhraseaApplication $app, Request $request)
|
||||||
{
|
{
|
||||||
if (null === $token = $request->get('token')) {
|
if (null === $tokenValue = $request->get('token')) {
|
||||||
$app->abort(401, 'A token is required');
|
$app->abort(401, 'A token is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (null === $token = $app['repo.tokens']->findValidToken($tokenValue)) {
|
||||||
$app['tokens']->helloToken($token);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$app->abort(401, 'A token is required');
|
$app->abort(401, 'A token is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
$form = $app->form(new PhraseaRecoverPasswordForm($app['tokens']));
|
$form = $app->form(new PhraseaRecoverPasswordForm($app['repo.tokens']));
|
||||||
$form->setData(['token' => $token]);
|
$form->setData(['token' => $token->getValue()]);
|
||||||
|
|
||||||
if ('POST' === $request->getMethod()) {
|
if ('POST' === $request->getMethod()) {
|
||||||
$form->bind($request);
|
$form->bind($request);
|
||||||
try {
|
|
||||||
if ($form->isValid()) {
|
if ($form->isValid()) {
|
||||||
$data = $form->getData();
|
$data = $form->getData();
|
||||||
|
$app['manipulator.user']->setPassword($token->getUser(), $data['password']);
|
||||||
$datas = $app['tokens']->helloToken($token);
|
$app['manipulator.token']->delete($token);
|
||||||
|
|
||||||
$user = $app['repo.users']->find($datas['usr_id']);
|
|
||||||
$app['manipulator.user']->setPassword($user, $data['password']);
|
|
||||||
|
|
||||||
$app['tokens']->removeToken($token);
|
|
||||||
|
|
||||||
$app->addFlash('success', $app->trans('login::notification: Mise a jour du mot de passe avec succes'));
|
$app->addFlash('success', $app->trans('login::notification: Mise a jour du mot de passe avec succes'));
|
||||||
|
|
||||||
return $app->redirectPath('homepage');
|
return $app->redirectPath('homepage');
|
||||||
}
|
}
|
||||||
} catch (FormProcessingException $e) {
|
|
||||||
$app->addFlash('error', $e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $app['twig']->render('login/renew-password.html.twig', array_merge(
|
return $app['twig']->render('login/renew-password.html.twig', array_merge(
|
||||||
@@ -649,13 +630,9 @@ class Login implements ControllerProviderInterface
|
|||||||
throw new FormProcessingException($app->trans('Invalid email address'));
|
throw new FormProcessingException($app->trans('Invalid email address'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$token = $app['tokens']->getUrlToken(\random::TYPE_PASSWORD, $user->getId(), new \DateTime('+1 day'));
|
$token = $app['manipulator.token']->createResetPasswordToken($user);
|
||||||
|
|
||||||
if (!$token) {
|
$url = $app->url('login_renew_password', ['token' => $token->getValue()], true);
|
||||||
return $app->abort(500, 'Unable to generate a token');
|
|
||||||
}
|
|
||||||
|
|
||||||
$url = $app->url('login_renew_password', ['token' => $token], true);
|
|
||||||
|
|
||||||
$mail = MailRequestPasswordUpdate::create($app, $receiver);
|
$mail = MailRequestPasswordUpdate::create($app, $receiver);
|
||||||
$mail->setLogin($user->getLogin());
|
$mail->setLogin($user->getLogin());
|
||||||
@@ -837,20 +814,18 @@ class Login implements ControllerProviderInterface
|
|||||||
|
|
||||||
$validationSession = $participant->getSession();
|
$validationSession = $participant->getSession();
|
||||||
$participantId = $participant->getUser()->getId();
|
$participantId = $participant->getUser()->getId();
|
||||||
$basketId = $validationSession->getBasket()->getId();
|
$basket = $validationSession->getBasket();
|
||||||
|
|
||||||
try {
|
if (null === $token = $app['repo.tokens']->findValidationToken($basket, $participant->getUser())) {
|
||||||
$token = $app['tokens']->getValidationToken($participantId, $basketId);
|
|
||||||
} catch (NotFoundHttpException $e) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$app['events-manager']->trigger('__VALIDATION_REMINDER__', [
|
$app['events-manager']->trigger('__VALIDATION_REMINDER__', [
|
||||||
'to' => $participantId,
|
'to' => $participantId,
|
||||||
'ssel_id' => $basketId,
|
'ssel_id' => $basket->getId(),
|
||||||
'from' => $validationSession->getInitiator()->getId(),
|
'from' => $validationSession->getInitiator()->getId(),
|
||||||
'validate_id' => $validationSession->getId(),
|
'validate_id' => $validationSession->getId(),
|
||||||
'url' => $app->url('lightbox_validation', ['basket' => $basketId, 'LOG' => $token]),
|
'url' => $app->url('lightbox_validation', ['basket' => $basket->getId(), 'LOG' => $token->getValue()]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$participant->setReminded(new \DateTime('now'));
|
$participant->setReminded(new \DateTime('now'));
|
||||||
|
@@ -25,6 +25,7 @@ class JsonRequestSubscriber implements EventSubscriberInterface
|
|||||||
|
|
||||||
if ((0 !== strpos($request->getPathInfo(), '/admin/')
|
if ((0 !== strpos($request->getPathInfo(), '/admin/')
|
||||||
|| 0 === strpos($request->getPathInfo(), '/admin/collection/')
|
|| 0 === strpos($request->getPathInfo(), '/admin/collection/')
|
||||||
|
|| preg_match('/^\/download\/[a-zA-Z0-9]+\/execute\/$/', $request->getPathInfo())
|
||||||
|| 0 === strpos($request->getPathInfo(), '/admin/databox/'))
|
|| 0 === strpos($request->getPathInfo(), '/admin/databox/'))
|
||||||
&& $request->getRequestFormat() == 'json') {
|
&& $request->getRequestFormat() == 'json') {
|
||||||
$datas = [
|
$datas = [
|
||||||
|
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Phraseanet
|
||||||
|
*
|
||||||
|
* (c) 2005-2014 Alchemy
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Alchemy\Phrasea\Core\Middleware;
|
||||||
|
|
||||||
|
use Silex\Application;
|
||||||
|
use Silex\ServiceProviderInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
class TokenMiddlewareProvider implements ServiceProviderInterface
|
||||||
|
{
|
||||||
|
public function register(Application $app)
|
||||||
|
{
|
||||||
|
$app['middleware.token.converter'] = $app->protect(function (Request $request, Application $app) {
|
||||||
|
if ($request->attributes->has('token')) {
|
||||||
|
$request->attributes->set('token', $app['converter.token']->convert($request->attributes->get('token')));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function boot(Application $app)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@@ -36,10 +36,6 @@ class AuthenticationManagerServiceProvider implements ServiceProviderInterface
|
|||||||
return new Authenticator($app, $app['browser'], $app['session'], $app['EM']);
|
return new Authenticator($app, $app['browser'], $app['session'], $app['EM']);
|
||||||
});
|
});
|
||||||
|
|
||||||
$app['authentication.token-validator'] = $app->share(function (Application $app) {
|
|
||||||
return new TokenValidator($app['tokens']);
|
|
||||||
});
|
|
||||||
|
|
||||||
$app['authentication.persistent-manager'] = $app->share(function (Application $app) {
|
$app['authentication.persistent-manager'] = $app->share(function (Application $app) {
|
||||||
return new CookieManager($app['auth.password-encoder'], $app['repo.sessions'], $app['browser']);
|
return new CookieManager($app['auth.password-encoder'], $app['repo.sessions'], $app['browser']);
|
||||||
});
|
});
|
||||||
|
@@ -15,6 +15,7 @@ use Alchemy\Phrasea\Setup\ConfigurationTester;
|
|||||||
use Alchemy\Phrasea\Application;
|
use Alchemy\Phrasea\Application;
|
||||||
use Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade\PreSchemaUpgradeCollection;
|
use Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade\PreSchemaUpgradeCollection;
|
||||||
use Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade\Upgrade39Feeds;
|
use Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade\Upgrade39Feeds;
|
||||||
|
use Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade\Upgrade39Tokens;
|
||||||
use Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade\Upgrade39Users;
|
use Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade\Upgrade39Users;
|
||||||
use Silex\Application as SilexApplication;
|
use Silex\Application as SilexApplication;
|
||||||
use Silex\ServiceProviderInterface;
|
use Silex\ServiceProviderInterface;
|
||||||
@@ -29,7 +30,7 @@ class ConfigurationTesterServiceProvider implements ServiceProviderInterface
|
|||||||
});
|
});
|
||||||
|
|
||||||
$app['phraseanet.pre-schema-upgrader.upgrades'] = $app->share(function () {
|
$app['phraseanet.pre-schema-upgrader.upgrades'] = $app->share(function () {
|
||||||
return [new Upgrade39Feeds(), new Upgrade39Users()];
|
return [new Upgrade39Feeds(), new Upgrade39Users(), new Upgrade39Tokens()];
|
||||||
});
|
});
|
||||||
|
|
||||||
$app['phraseanet.pre-schema-upgrader'] = $app->share(function (Application $app) {
|
$app['phraseanet.pre-schema-upgrader'] = $app->share(function (Application $app) {
|
||||||
|
@@ -13,6 +13,7 @@ namespace Alchemy\Phrasea\Core\Provider;
|
|||||||
|
|
||||||
use Alchemy\Phrasea\Model\Converter\BasketConverter;
|
use Alchemy\Phrasea\Model\Converter\BasketConverter;
|
||||||
use Alchemy\Phrasea\Model\Converter\TaskConverter;
|
use Alchemy\Phrasea\Model\Converter\TaskConverter;
|
||||||
|
use Alchemy\Phrasea\Model\Converter\TokenConverter;
|
||||||
use Silex\Application;
|
use Silex\Application;
|
||||||
use Silex\ServiceProviderInterface;
|
use Silex\ServiceProviderInterface;
|
||||||
|
|
||||||
@@ -27,6 +28,10 @@ class ConvertersServiceProvider implements ServiceProviderInterface
|
|||||||
$app['converter.basket'] = $app->share(function ($app) {
|
$app['converter.basket'] = $app->share(function ($app) {
|
||||||
return new BasketConverter($app['EM']);
|
return new BasketConverter($app['EM']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$app['converter.token'] = $app->share(function ($app) {
|
||||||
|
return new TokenConverter($app['repo.tokens']);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function boot(Application $app)
|
public function boot(Application $app)
|
||||||
|
@@ -14,6 +14,7 @@ namespace Alchemy\Phrasea\Core\Provider;
|
|||||||
use Alchemy\Phrasea\Model\Manipulator\ACLManipulator;
|
use Alchemy\Phrasea\Model\Manipulator\ACLManipulator;
|
||||||
use Alchemy\Phrasea\Model\Manipulator\RegistrationManipulator;
|
use Alchemy\Phrasea\Model\Manipulator\RegistrationManipulator;
|
||||||
use Alchemy\Phrasea\Model\Manipulator\TaskManipulator;
|
use Alchemy\Phrasea\Model\Manipulator\TaskManipulator;
|
||||||
|
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||||
use Alchemy\Phrasea\Model\Manipulator\UserManipulator;
|
use Alchemy\Phrasea\Model\Manipulator\UserManipulator;
|
||||||
use Alchemy\Phrasea\Model\Manager\UserManager;
|
use Alchemy\Phrasea\Model\Manager\UserManager;
|
||||||
use Silex\Application as SilexApplication;
|
use Silex\Application as SilexApplication;
|
||||||
@@ -31,6 +32,10 @@ class ManipulatorServiceProvider implements ServiceProviderInterface
|
|||||||
return new UserManipulator($app['model.user-manager'], $app['auth.password-encoder'], $app['geonames.connector'], $app['repo.users'], $app['random.low']);
|
return new UserManipulator($app['model.user-manager'], $app['auth.password-encoder'], $app['geonames.connector'], $app['repo.users'], $app['random.low']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$app['manipulator.token'] = $app->share(function ($app) {
|
||||||
|
return new TokenManipulator($app['EM'], $app['random.medium'], $app['repo.tokens']);
|
||||||
|
});
|
||||||
|
|
||||||
$app['manipulator.acl'] = $app->share(function ($app) {
|
$app['manipulator.acl'] = $app->share(function ($app) {
|
||||||
return new ACLManipulator($app['acl'], $app['phraseanet.appbox']);
|
return new ACLManipulator($app['acl'], $app['phraseanet.appbox']);
|
||||||
});
|
});
|
||||||
|
@@ -91,6 +91,9 @@ class RepositoriesServiceProvider implements ServiceProviderInterface
|
|||||||
$app['repo.user-queries'] = $app->share(function (PhraseaApplication $app) {
|
$app['repo.user-queries'] = $app->share(function (PhraseaApplication $app) {
|
||||||
return $app['EM']->getRepository('Phraseanet:UserQuery');
|
return $app['EM']->getRepository('Phraseanet:UserQuery');
|
||||||
});
|
});
|
||||||
|
$app['repo.tokens'] = $app->share(function ($app) {
|
||||||
|
return $app['EM']->getRepository('Phraseanet:Token');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function boot(Application $app)
|
public function boot(Application $app)
|
||||||
|
@@ -16,6 +16,7 @@ use Alchemy\Phrasea\Feed\Aggregate;
|
|||||||
use Alchemy\Phrasea\Feed\FeedInterface;
|
use Alchemy\Phrasea\Feed\FeedInterface;
|
||||||
use Alchemy\Phrasea\Model\Entities\AggregateToken;
|
use Alchemy\Phrasea\Model\Entities\AggregateToken;
|
||||||
use Alchemy\Phrasea\Model\Entities\User;
|
use Alchemy\Phrasea\Model\Entities\User;
|
||||||
|
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||||
use Doctrine\ORM\EntityManager;
|
use Doctrine\ORM\EntityManager;
|
||||||
use RandomLib\Generator;
|
use RandomLib\Generator;
|
||||||
use Symfony\Component\Routing\Generator\UrlGenerator;
|
use Symfony\Component\Routing\Generator\UrlGenerator;
|
||||||
@@ -141,7 +142,7 @@ class AggregateLinkGenerator implements LinkGeneratorInterface
|
|||||||
$token->setUser($user);
|
$token->setUser($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
$token->setValue($this->random->generateString(64, \random::LETTERS_AND_NUMBERS));
|
$token->setValue($this->random->generateString(64, TokenManipulator::LETTERS_AND_NUMBERS));
|
||||||
$this->em->persist($token);
|
$this->em->persist($token);
|
||||||
$this->em->flush();
|
$this->em->flush();
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,7 @@ namespace Alchemy\Phrasea\Feed\Link;
|
|||||||
use Alchemy\Phrasea\Exception\InvalidArgumentException;
|
use Alchemy\Phrasea\Exception\InvalidArgumentException;
|
||||||
use Alchemy\Phrasea\Feed\FeedInterface;
|
use Alchemy\Phrasea\Feed\FeedInterface;
|
||||||
use Alchemy\Phrasea\Model\Entities\User;
|
use Alchemy\Phrasea\Model\Entities\User;
|
||||||
|
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||||
use Doctrine\ORM\EntityManager;
|
use Doctrine\ORM\EntityManager;
|
||||||
use Alchemy\Phrasea\Model\Entities\Feed;
|
use Alchemy\Phrasea\Model\Entities\Feed;
|
||||||
use Alchemy\Phrasea\Model\Entities\FeedToken;
|
use Alchemy\Phrasea\Model\Entities\FeedToken;
|
||||||
@@ -153,7 +154,7 @@ class FeedLinkGenerator implements LinkGeneratorInterface
|
|||||||
$this->em->persist($feed);
|
$this->em->persist($feed);
|
||||||
}
|
}
|
||||||
|
|
||||||
$token->setValue($this->random->generateString(64, \random::LETTERS_AND_NUMBERS));
|
$token->setValue($this->random->generateString(64, TokenManipulator::LETTERS_AND_NUMBERS));
|
||||||
$this->em->persist($token);
|
$this->em->persist($token);
|
||||||
$this->em->flush();
|
$this->em->flush();
|
||||||
}
|
}
|
||||||
|
@@ -12,33 +12,33 @@
|
|||||||
namespace Alchemy\Phrasea\Form\Constraint;
|
namespace Alchemy\Phrasea\Form\Constraint;
|
||||||
|
|
||||||
use Alchemy\Phrasea\Application;
|
use Alchemy\Phrasea\Application;
|
||||||
|
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
use Symfony\Component\Validator\Constraint;
|
use Symfony\Component\Validator\Constraint;
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
|
||||||
class PasswordToken extends Constraint
|
class PasswordToken extends Constraint
|
||||||
{
|
{
|
||||||
public $message = 'The token provided is not valid anymore';
|
public $message = 'The token provided is not valid anymore';
|
||||||
private $random;
|
private $repository;
|
||||||
|
|
||||||
public function __construct(\random $random)
|
public function __construct(EntityRepository $repository)
|
||||||
{
|
{
|
||||||
$this->random = $random;
|
$this->repository = $repository;
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isValid($token)
|
public function isValid($tokenValue)
|
||||||
{
|
{
|
||||||
try {
|
if (null === $token = $this->repository->findValidToken($tokenValue)) {
|
||||||
$data = $this->random->helloToken($token);
|
|
||||||
} catch (NotFoundHttpException $e) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return \random::TYPE_PASSWORD === $data['type'];
|
return TokenManipulator::TYPE_PASSWORD === $token->getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function create(Application $app)
|
public static function create(Application $app)
|
||||||
{
|
{
|
||||||
return new static($app['tokens']);
|
return new static($app['repo.tokens']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
namespace Alchemy\Phrasea\Form\Login;
|
namespace Alchemy\Phrasea\Form\Login;
|
||||||
|
|
||||||
use Alchemy\Phrasea\Form\Constraint\PasswordToken;
|
use Alchemy\Phrasea\Form\Constraint\PasswordToken;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
@@ -21,11 +22,11 @@ use Symfony\Component\Validator\Constraints as Assert;
|
|||||||
*/
|
*/
|
||||||
class PhraseaRecoverPasswordForm extends AbstractType
|
class PhraseaRecoverPasswordForm extends AbstractType
|
||||||
{
|
{
|
||||||
private $tokens;
|
private $repository;
|
||||||
|
|
||||||
public function __construct(\random $tokens)
|
public function __construct(EntityRepository $repository)
|
||||||
{
|
{
|
||||||
$this->tokens = $tokens;
|
$this->repository = $repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
@@ -33,7 +34,7 @@ class PhraseaRecoverPasswordForm extends AbstractType
|
|||||||
$builder->add('token', 'hidden', [
|
$builder->add('token', 'hidden', [
|
||||||
'required' => true,
|
'required' => true,
|
||||||
'constraints' => [
|
'constraints' => [
|
||||||
new PasswordToken($this->tokens)
|
new PasswordToken($this->repository)
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@@ -159,30 +159,24 @@ class Manage extends Helper
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($sendCredentials) {
|
if ($sendCredentials && $receiver) {
|
||||||
$urlToken = $this->app['tokens']->getUrlToken(\random::TYPE_PASSWORD, $createdUser->getId());
|
$urlToken = $this->app['manipulator.token']->createResetPasswordToken($createdUser);
|
||||||
|
$url = $this->app->url('login_renew_password', ['token' => $urlToken->getValue()]);
|
||||||
if ($receiver && false !== $urlToken) {
|
|
||||||
$url = $this->app->url('login_renew_password', ['token' => $urlToken]);
|
|
||||||
$mail = MailRequestPasswordSetup::create($this->app, $receiver, null, '', $url);
|
$mail = MailRequestPasswordSetup::create($this->app, $receiver, null, '', $url);
|
||||||
$mail->setLogin($createdUser->getLogin());
|
$mail->setLogin($createdUser->getLogin());
|
||||||
$this->app['notification.deliverer']->deliver($mail);
|
$this->app['notification.deliverer']->deliver($mail);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ($validateMail) {
|
if ($validateMail && $receiver) {
|
||||||
$createdUser->setMailLocked(true);
|
$createdUser->setMailLocked(true);
|
||||||
|
|
||||||
if ($receiver) {
|
$token = $this->app['manipulator.token']->createAccountUnlockToken($createdUser);
|
||||||
$expire = new \DateTime('+3 days');
|
|
||||||
$token = $this->app['tokens']->getUrlToken(\random::TYPE_PASSWORD, $createdUser->getId(), $expire, $createdUser->getEmail());
|
|
||||||
$url = $this->app->url('login_register_confirm', ['code' => $token]);
|
$url = $this->app->url('login_register_confirm', ['code' => $token]);
|
||||||
|
|
||||||
$mail = MailRequestEmailConfirmation::create($this->app, $receiver, null, '', $url, $expire);
|
$mail = MailRequestEmailConfirmation::create($this->app, $receiver, null, '', $url, $token->getExpiration());
|
||||||
$this->app['notification.deliverer']->deliver($mail);
|
$this->app['notification.deliverer']->deliver($mail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$this->usr_id = $createdUser->getId();
|
$this->usr_id = $createdUser->getId();
|
||||||
|
|
||||||
|
40
lib/Alchemy/Phrasea/Model/Converter/TokenConverter.php
Normal file
40
lib/Alchemy/Phrasea/Model/Converter/TokenConverter.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Phraseanet
|
||||||
|
*
|
||||||
|
* (c) 2005-2014 Alchemy
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Alchemy\Phrasea\Model\Converter;
|
||||||
|
|
||||||
|
use Alchemy\Phrasea\Model\Entities\Token;
|
||||||
|
use Alchemy\Phrasea\Model\Repositories\TokenRepository;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
|
||||||
|
class TokenConverter implements ConverterInterface
|
||||||
|
{
|
||||||
|
private $repository;
|
||||||
|
|
||||||
|
public function __construct(TokenRepository $repository)
|
||||||
|
{
|
||||||
|
$this->repository = $repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function convert($value)
|
||||||
|
{
|
||||||
|
if (null === $token = $this->repository->findValidToken($value)) {
|
||||||
|
throw new NotFoundHttpException('Token is not valid.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
}
|
222
lib/Alchemy/Phrasea/Model/Entities/Token.php
Normal file
222
lib/Alchemy/Phrasea/Model/Entities/Token.php
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Phraseanet
|
||||||
|
*
|
||||||
|
* (c) 2005-2014 Alchemy
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Alchemy\Phrasea\Model\Entities;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Gedmo\Mapping\Annotation as Gedmo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Table(name="Tokens")
|
||||||
|
* @ORM\Entity(repositoryClass="Alchemy\Phrasea\Model\Repositories\TokenRepository")
|
||||||
|
*/
|
||||||
|
class Token
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\Column(type="string", length=16)
|
||||||
|
*/
|
||||||
|
private $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity="User")
|
||||||
|
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=true)
|
||||||
|
**/
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="string", length=32)
|
||||||
|
*/
|
||||||
|
private $type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="text", nullable=true)
|
||||||
|
*/
|
||||||
|
private $data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Gedmo\Timestampable(on="create")
|
||||||
|
* @ORM\Column(type="datetime")
|
||||||
|
*/
|
||||||
|
private $created;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Gedmo\Timestampable(on="update")
|
||||||
|
* @ORM\Column(type="datetime")
|
||||||
|
*/
|
||||||
|
private $updated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="datetime", nullable=true)
|
||||||
|
*/
|
||||||
|
private $expiration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set value
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function setValue($value)
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get value
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValue()
|
||||||
|
{
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set type
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function setType($type)
|
||||||
|
{
|
||||||
|
$this->type = $type;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get type
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getType()
|
||||||
|
{
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set data
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function setData($data)
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get data
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getData()
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set created
|
||||||
|
*
|
||||||
|
* @param \DateTime $created
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function setCreated($created)
|
||||||
|
{
|
||||||
|
$this->created = $created;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get created
|
||||||
|
*
|
||||||
|
* @return \DateTime
|
||||||
|
*/
|
||||||
|
public function getCreated()
|
||||||
|
{
|
||||||
|
return $this->created;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set updated
|
||||||
|
*
|
||||||
|
* @param \DateTime $updated
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function setUpdated($updated)
|
||||||
|
{
|
||||||
|
$this->updated = $updated;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get updated
|
||||||
|
*
|
||||||
|
* @return \DateTime
|
||||||
|
*/
|
||||||
|
public function getUpdated()
|
||||||
|
{
|
||||||
|
return $this->updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set expiration
|
||||||
|
*
|
||||||
|
* @param \DateTime $updated
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function setExpiration(\DateTime $expiration = null)
|
||||||
|
{
|
||||||
|
$this->expiration = $expiration;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get expiration
|
||||||
|
*
|
||||||
|
* @return \DateTime
|
||||||
|
*/
|
||||||
|
public function getExpiration()
|
||||||
|
{
|
||||||
|
return $this->expiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set user
|
||||||
|
*
|
||||||
|
* @param User $user
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function setUser(User $user = null)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get user
|
||||||
|
*
|
||||||
|
* @return User
|
||||||
|
*/
|
||||||
|
public function getUser()
|
||||||
|
{
|
||||||
|
return $this->user;
|
||||||
|
}
|
||||||
|
}
|
@@ -101,6 +101,16 @@ class UserManager
|
|||||||
$user->getSettings()->clear();
|
$user->getSettings()->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function cleanTokens(User $user)
|
||||||
|
{
|
||||||
|
$elements = $this->objectManager->getRepository('Phraseanet:Token')
|
||||||
|
->findBy(['user' => $user]);
|
||||||
|
|
||||||
|
foreach ($elements as $element) {
|
||||||
|
$this->objectManager->remove($element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes user queries.
|
* Removes user queries.
|
||||||
*
|
*
|
||||||
@@ -194,16 +204,13 @@ class UserManager
|
|||||||
*/
|
*/
|
||||||
private function cleanProperties(User $user)
|
private function cleanProperties(User $user)
|
||||||
{
|
{
|
||||||
foreach ([
|
$sql = 'DELETE FROM `edit_presets` WHERE usr_id = :usr_id';
|
||||||
'DELETE FROM `edit_presets` WHERE usr_id = :usr_id',
|
|
||||||
'DELETE FROM `tokens` WHERE usr_id = :usr_id',
|
|
||||||
] as $sql) {
|
|
||||||
$stmt = $this->appboxConnection->prepare($sql);
|
$stmt = $this->appboxConnection->prepare($sql);
|
||||||
$stmt->execute([':usr_id' => $user->getId()]);
|
$stmt->execute([':usr_id' => $user->getId()]);
|
||||||
$stmt->closeCursor();
|
$stmt->closeCursor();
|
||||||
}
|
|
||||||
|
|
||||||
$this->cleanSettings($user);
|
$this->cleanSettings($user);
|
||||||
|
$this->cleanTokens($user);
|
||||||
$this->cleanQueries($user);
|
$this->cleanQueries($user);
|
||||||
$this->cleanFtpCredentials($user);
|
$this->cleanFtpCredentials($user);
|
||||||
$this->cleanOrders($user);
|
$this->cleanOrders($user);
|
||||||
|
219
lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php
Normal file
219
lib/Alchemy/Phrasea/Model/Manipulator/TokenManipulator.php
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Phraseanet
|
||||||
|
*
|
||||||
|
* (c) 2005-2014 Alchemy
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Alchemy\Phrasea\Model\Manipulator;
|
||||||
|
|
||||||
|
use Alchemy\Phrasea\Model\Entities\Basket;
|
||||||
|
use Alchemy\Phrasea\Model\Entities\FeedEntry;
|
||||||
|
use Alchemy\Phrasea\Model\Entities\Token;
|
||||||
|
use Alchemy\Phrasea\Model\Entities\User;
|
||||||
|
use Alchemy\Phrasea\Model\Repositories\TokenRepository;
|
||||||
|
use Doctrine\Common\Persistence\ObjectManager;
|
||||||
|
use Doctrine\ORM\Query;
|
||||||
|
use RandomLib\Generator;
|
||||||
|
|
||||||
|
class TokenManipulator implements ManipulatorInterface
|
||||||
|
{
|
||||||
|
const LETTERS_AND_NUMBERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
|
const TYPE_FEED_ENTRY = 'FEED_ENTRY';
|
||||||
|
const TYPE_PASSWORD = 'password';
|
||||||
|
const TYPE_ACCOUNT_UNLOCK = 'account-unlock';
|
||||||
|
const TYPE_DOWNLOAD = 'download';
|
||||||
|
const TYPE_MAIL_DOWNLOAD = 'mail-download';
|
||||||
|
const TYPE_EMAIL = 'email';
|
||||||
|
const TYPE_EMAIL_RESET = 'email-reset';
|
||||||
|
const TYPE_VIEW = 'view';
|
||||||
|
const TYPE_VALIDATE = 'validate';
|
||||||
|
const TYPE_RSS = 'rss';
|
||||||
|
|
||||||
|
/** @var Objectmanager */
|
||||||
|
private $om;
|
||||||
|
private $random;
|
||||||
|
private $repository;
|
||||||
|
|
||||||
|
public function __construct(ObjectManager $om, Generator $random, TokenRepository $repository)
|
||||||
|
{
|
||||||
|
$this->om = $om;
|
||||||
|
$this->random = $random;
|
||||||
|
$this->repository = $repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param User|null $user
|
||||||
|
* @param string $type
|
||||||
|
* @param \DateTime|null $expiration
|
||||||
|
* @param mixed|null $data
|
||||||
|
*
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function create(User $user = null, $type, \DateTime $expiration = null, $data = null)
|
||||||
|
{
|
||||||
|
$this->removeExpiredTokens();
|
||||||
|
|
||||||
|
$n = 0;
|
||||||
|
do {
|
||||||
|
if ($n++ > 1024) {
|
||||||
|
throw new \RuntimeException('Unable to create a token.');
|
||||||
|
}
|
||||||
|
$value = $this->random->generateString(32, self::LETTERS_AND_NUMBERS);
|
||||||
|
$found = null !== $this->om->getRepository('Phraseanet:Token')->find($value);
|
||||||
|
} while ($found);
|
||||||
|
|
||||||
|
$token = new Token();
|
||||||
|
|
||||||
|
$token->setUser($user)
|
||||||
|
->setType($type)
|
||||||
|
->setValue($value)
|
||||||
|
->setExpiration($expiration)
|
||||||
|
->setData($data);
|
||||||
|
|
||||||
|
$this->om->persist($token);
|
||||||
|
$this->om->flush();
|
||||||
|
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Basket $basket
|
||||||
|
* @param User $user
|
||||||
|
*
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function createBasketValidationToken(Basket $basket, User $user = null)
|
||||||
|
{
|
||||||
|
if (null === $basket->getValidation()) {
|
||||||
|
throw new \InvalidArgumentException('A validation token requires a validation basket.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->create($user ?: $basket->getValidation()->getInitiator(), self::TYPE_VALIDATE, new \DateTime('+10 days'), $basket->getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Basket $basket
|
||||||
|
* @param User $user
|
||||||
|
*
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function createBasketAccessToken(Basket $basket, User $user)
|
||||||
|
{
|
||||||
|
return $this->create($user, self::TYPE_VIEW, null, $basket->getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param User $user
|
||||||
|
* @param FeedEntry $entry
|
||||||
|
*
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function createFeedEntryToken(User $user, FeedEntry $entry)
|
||||||
|
{
|
||||||
|
return $this->create($user, self::TYPE_FEED_ENTRY, null, $entry->getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param User $user
|
||||||
|
* @param $data
|
||||||
|
*
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function createDownloadToken(User $user, $data)
|
||||||
|
{
|
||||||
|
return $this->create($user, self::TYPE_DOWNLOAD, new \DateTime('+3 hours'), $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $data
|
||||||
|
*
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function createEmailExportToken($data)
|
||||||
|
{
|
||||||
|
return $this->create(null, self::TYPE_EMAIL, new \DateTime('+1 day'), $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param User $user
|
||||||
|
* @param $email
|
||||||
|
*
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function createResetEmailToken(User $user, $email)
|
||||||
|
{
|
||||||
|
return $this->create($user, self::TYPE_EMAIL_RESET, new \DateTime('+1 day'), $email);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param User $user
|
||||||
|
*
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function createAccountUnlockToken(User $user)
|
||||||
|
{
|
||||||
|
return $this->create($user, self::TYPE_ACCOUNT_UNLOCK, new \DateTime('+3 days'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param User $user
|
||||||
|
*
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function createResetPasswordToken(User $user)
|
||||||
|
{
|
||||||
|
return $this->create($user, self::TYPE_PASSWORD, new \DateTime('+1 day'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a token.
|
||||||
|
*
|
||||||
|
* @param Token $token
|
||||||
|
*
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
public function update(Token $token)
|
||||||
|
{
|
||||||
|
$this->om->persist($token);
|
||||||
|
$this->om->flush();
|
||||||
|
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a token.
|
||||||
|
*
|
||||||
|
* @param Token $token
|
||||||
|
*/
|
||||||
|
public function delete(Token $token)
|
||||||
|
{
|
||||||
|
$this->om->remove($token);
|
||||||
|
$this->om->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes expired tokens
|
||||||
|
*/
|
||||||
|
public function removeExpiredTokens()
|
||||||
|
{
|
||||||
|
foreach ($this->repository->findExpiredTokens() as $token) {
|
||||||
|
switch ($token->getType()) {
|
||||||
|
case 'download':
|
||||||
|
case 'email':
|
||||||
|
$file = $this->app['root.path'] . '/tmp/download/' . $token->getValue() . '.zip';
|
||||||
|
if (is_file($file)) {
|
||||||
|
unlink($file);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$this->om->remove($token);
|
||||||
|
}
|
||||||
|
$this->om->flush();
|
||||||
|
}
|
||||||
|
}
|
59
lib/Alchemy/Phrasea/Model/Repositories/TokenRepository.php
Normal file
59
lib/Alchemy/Phrasea/Model/Repositories/TokenRepository.php
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Alchemy\Phrasea\Model\Repositories;
|
||||||
|
|
||||||
|
use Alchemy\Phrasea\Model\Entities\Basket;
|
||||||
|
use Alchemy\Phrasea\Model\Entities\User;
|
||||||
|
use Alchemy\Phrasea\Model\Entities\ValidationParticipant;
|
||||||
|
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TokenRepository
|
||||||
|
*
|
||||||
|
* This class was generated by the Doctrine ORM. Add your own custom
|
||||||
|
* repository methods below.
|
||||||
|
*/
|
||||||
|
class TokenRepository extends EntityRepository
|
||||||
|
{
|
||||||
|
public function findValidationToken(Basket $basket, User $user)
|
||||||
|
{
|
||||||
|
$dql = 'SELECT t FROM Phraseanet:Token t
|
||||||
|
WHERE t.type = :type
|
||||||
|
AND t.user = :user
|
||||||
|
AND t.data = :basket_id
|
||||||
|
AND (t.expiration > CURRENT_TIMESTAMP() OR t.expiration IS NULL)';
|
||||||
|
|
||||||
|
$query = $this->_em->createQuery($dql);
|
||||||
|
$query->setParameters([
|
||||||
|
':type' => TokenManipulator::TYPE_VALIDATE,
|
||||||
|
':user' => $user,
|
||||||
|
':basket_id' => $basket->getId(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $query->getOneOrNullResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findValidToken($value)
|
||||||
|
{
|
||||||
|
$dql = 'SELECT t FROM Phraseanet:Token t
|
||||||
|
WHERE t.value = :value
|
||||||
|
AND (t.expiration IS NULL OR t.expiration >= CURRENT_TIMESTAMP())';
|
||||||
|
|
||||||
|
$query = $this->_em->createQuery($dql);
|
||||||
|
$query->setParameters([':value' => $value]);
|
||||||
|
|
||||||
|
return $query->getOneOrNullResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findExpiredTokens()
|
||||||
|
{
|
||||||
|
$dql = 'SELECT t FROM Phraseanet:Token t
|
||||||
|
WHERE t.expiration < :date';
|
||||||
|
|
||||||
|
$query = $this->_em->createQuery($dql);
|
||||||
|
$query->setParameters([':date' => new \DateTime()]);
|
||||||
|
|
||||||
|
return $query->getResult();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Phraseanet
|
||||||
|
*
|
||||||
|
* (c) 2005-2014 Alchemy
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Alchemy\Phrasea\Setup\DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
|
||||||
|
class TokenMigration extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function doUpSql(Schema $schema)
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql", "Migration can only be executed safely on 'mysql'.");
|
||||||
|
|
||||||
|
$this->addSql("CREATE TABLE Tokens (value VARCHAR(16) NOT NULL, user_id INT DEFAULT NULL, type VARCHAR(32) NOT NULL, data LONGTEXT DEFAULT NULL, created DATETIME NOT NULL, updated DATETIME NOT NULL, expiration DATETIME DEFAULT NULL, INDEX IDX_ADF614B8A76ED395 (user_id), PRIMARY KEY(value)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB");
|
||||||
|
$this->addSql("ALTER TABLE Tokens ADD CONSTRAINT FK_ADF614B8A76ED395 FOREIGN KEY (user_id) REFERENCES Users (id)");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function doDownSql(Schema $schema)
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql", "Migration can only be executed safely on 'mysql'.");
|
||||||
|
|
||||||
|
$this->addSql("DROP TABLE Tokens");
|
||||||
|
}
|
||||||
|
}
|
@@ -41,7 +41,7 @@ class Upgrade39Feeds implements PreSchemaUpgradeInterface
|
|||||||
public function rollback(EntityManager $em, \appbox $appbox, Configuration $conf)
|
public function rollback(EntityManager $em, \appbox $appbox, Configuration $conf)
|
||||||
{
|
{
|
||||||
if ($this->tableExists($em, 'feeds_backup')) {
|
if ($this->tableExists($em, 'feeds_backup')) {
|
||||||
$em->getConnection()->executeUpdate('RENAME TABLE `feeds_backup` TO `feeds`');
|
$em->getConnection()->getSchemaManager()->renameTable('feeds_backup', 'feeds');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,6 +67,6 @@ class Upgrade39Feeds implements PreSchemaUpgradeInterface
|
|||||||
*/
|
*/
|
||||||
private function doBackupFeedsTable(EntityManager $em)
|
private function doBackupFeedsTable(EntityManager $em)
|
||||||
{
|
{
|
||||||
$em->getConnection()->executeUpdate('RENAME TABLE `feeds` TO `feeds_backup`');
|
$em->getConnection()->getSchemaManager()->renameTable('feeds', 'feeds_backup');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Phraseanet
|
||||||
|
*
|
||||||
|
* (c) 2005-2014 Alchemy
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Alchemy\Phrasea\Setup\Version\PreSchemaUpgrade;
|
||||||
|
|
||||||
|
use Alchemy\Phrasea\Application;
|
||||||
|
use Alchemy\Phrasea\Model\Entities\User;
|
||||||
|
use Alchemy\Phrasea\Model\Entities\FtpCredential;
|
||||||
|
use Doctrine\DBAL\Migrations\Configuration\Configuration;
|
||||||
|
use Doctrine\ORM\EntityManager;
|
||||||
|
use Doctrine\ORM\NoResultException;
|
||||||
|
use Doctrine\ORM\Query;
|
||||||
|
use Doctrine\ORM\Query\ResultSetMapping;
|
||||||
|
|
||||||
|
class Upgrade39Tokens implements PreSchemaUpgradeInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function apply(EntityManager $em, \appbox $appbox, Configuration $conf)
|
||||||
|
{
|
||||||
|
$this->doBackupFeedsTable($em);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function isApplyable(Application $app)
|
||||||
|
{
|
||||||
|
return $this->tableExists($app['EM'], 'tokens');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function rollback(EntityManager $em, \appbox $appbox, Configuration $conf)
|
||||||
|
{
|
||||||
|
if ($this->tableExists($em, 'tokens_backup')) {
|
||||||
|
$em->getConnection()->executeUpdate('RENAME TABLE `tokens_backup` TO `tokens`');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the table exists or not.
|
||||||
|
*
|
||||||
|
* @param $tableName
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
|
||||||
|
private function tableExists(EntityManager $em, $table)
|
||||||
|
{
|
||||||
|
return (Boolean) $em->createNativeQuery(
|
||||||
|
'SHOW TABLE STATUS WHERE Name="'.$table.'" COLLATE utf8_bin ', (new ResultSetMapping())->addScalarResult('Name', 'Name')
|
||||||
|
)->getOneOrNullResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renames feed table.
|
||||||
|
*
|
||||||
|
* @param EntityManager $em
|
||||||
|
*/
|
||||||
|
private function doBackupFeedsTable(EntityManager $em)
|
||||||
|
{
|
||||||
|
$em->getConnection()->executeUpdate('RENAME TABLE `tokens` TO `tokens_backup`');
|
||||||
|
}
|
||||||
|
}
|
@@ -10,8 +10,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use Alchemy\Phrasea\Application;
|
use Alchemy\Phrasea\Application;
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|
||||||
use Alchemy\Phrasea\Model\Entities\User;
|
use Alchemy\Phrasea\Model\Entities\User;
|
||||||
|
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
|
||||||
class API_OAuth2_Application
|
class API_OAuth2_Application
|
||||||
{
|
{
|
||||||
@@ -606,8 +607,8 @@ class API_OAuth2_Application
|
|||||||
)';
|
)';
|
||||||
|
|
||||||
$nonce = $app['random.medium']->generateString(64);
|
$nonce = $app['random.medium']->generateString(64);
|
||||||
$client_secret = $app['random.medium']->generateString(32, \random::LETTERS_AND_NUMBERS);
|
$client_secret = $app['random.medium']->generateString(32, TokenManipulator::LETTERS_AND_NUMBERS);
|
||||||
$client_token = $app['random.medium']->generateString(32, \random::LETTERS_AND_NUMBERS);
|
$client_token = $app['random.medium']->generateString(32, TokenManipulator::LETTERS_AND_NUMBERS);
|
||||||
|
|
||||||
$params = [
|
$params = [
|
||||||
':usr_id' => $user ? $user->getId() : null,
|
':usr_id' => $user ? $user->getId() : null,
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use Alchemy\Phrasea\Application;
|
use Alchemy\Phrasea\Application;
|
||||||
|
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||||
use RandomLib\Generator;
|
use RandomLib\Generator;
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
|
||||||
@@ -230,7 +231,7 @@ class API_OAuth2_Token
|
|||||||
$sql = 'UPDATE api_oauth_tokens SET oauth_token = :new_token
|
$sql = 'UPDATE api_oauth_tokens SET oauth_token = :new_token
|
||||||
WHERE oauth_token = :old_token';
|
WHERE oauth_token = :old_token';
|
||||||
|
|
||||||
$new_token = $this->generator->generateString(32, \random::LETTERS_AND_NUMBERS);
|
$new_token = $this->generator->generateString(32, TokenManipulator::LETTERS_AND_NUMBERS);
|
||||||
|
|
||||||
$params = [
|
$params = [
|
||||||
':new_token' => $new_token
|
':new_token' => $new_token
|
||||||
@@ -303,7 +304,7 @@ class API_OAuth2_Token
|
|||||||
$expires = new \DateTime('+1 hour');
|
$expires = new \DateTime('+1 hour');
|
||||||
|
|
||||||
$params = [
|
$params = [
|
||||||
':token' => $generator->generateString(32, \random::LETTERS_AND_NUMBERS)
|
':token' => $generator->generateString(32, TokenManipulator::LETTERS_AND_NUMBERS)
|
||||||
, ':account_id' => $account->get_id()
|
, ':account_id' => $account->get_id()
|
||||||
, ':expire' => $expires->format(DATE_ISO8601)
|
, ':expire' => $expires->format(DATE_ISO8601)
|
||||||
, ':scope' => $scope
|
, ':scope' => $scope
|
||||||
|
@@ -88,14 +88,8 @@ class eventsmanager_notify_feed extends eventsmanager_notifyAbstract
|
|||||||
if ($params['notify_email'] && $this->shouldSendNotificationFor($user_to_notif->getId())) {
|
if ($params['notify_email'] && $this->shouldSendNotificationFor($user_to_notif->getId())) {
|
||||||
$readyToSend = false;
|
$readyToSend = false;
|
||||||
try {
|
try {
|
||||||
$token = $this->app['tokens']->getUrlToken(
|
$token = $this->app['manipulator.token']->createFeedEntryToken($user_to_notif, $entry);
|
||||||
\random::TYPE_FEED_ENTRY
|
$url = $this->app->url('lightbox', ['LOG' => $token->getValue()]);
|
||||||
, $user_to_notif->getId()
|
|
||||||
, null
|
|
||||||
, $entry->getId()
|
|
||||||
);
|
|
||||||
|
|
||||||
$url = $this->app->url('lightbox', ['LOG' => $token]);
|
|
||||||
|
|
||||||
$receiver = Receiver::fromUser($user_to_notif);
|
$receiver = Receiver::fromUser($user_to_notif);
|
||||||
$readyToSend = true;
|
$readyToSend = true;
|
||||||
|
@@ -109,12 +109,7 @@ class eventsmanager_notify_orderdeliver extends eventsmanager_notifyAbstract
|
|||||||
if ($readyToSend) {
|
if ($readyToSend) {
|
||||||
$url = $this->app->url('lightbox_compare', [
|
$url = $this->app->url('lightbox_compare', [
|
||||||
'basket' => $basket->getId(),
|
'basket' => $basket->getId(),
|
||||||
'LOG' => $this->app['tokens']->getUrlToken(
|
'LOG' => $this->app['manipulator.token']->createBasketAccessToken($basket, $user_to)->getValue(),
|
||||||
\random::TYPE_VIEW,
|
|
||||||
$user_to->getId(),
|
|
||||||
null,
|
|
||||||
$basket->getId()
|
|
||||||
)
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$mail = MailInfoOrderDelivered::create($this->app, $receiver, $emitter, null);
|
$mail = MailInfoOrderDelivered::create($this->app, $receiver, $emitter, null);
|
||||||
|
@@ -11,8 +11,9 @@
|
|||||||
|
|
||||||
use Alchemy\Phrasea\Application;
|
use Alchemy\Phrasea\Application;
|
||||||
use Alchemy\Phrasea\Exception\RuntimeException;
|
use Alchemy\Phrasea\Exception\RuntimeException;
|
||||||
use Guzzle\Http\Url;
|
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||||
use Doctrine\DBAL\DBALException;
|
use Doctrine\DBAL\DBALException;
|
||||||
|
use Guzzle\Http\Url;
|
||||||
|
|
||||||
class media_Permalink_Adapter implements media_Permalink_Interface, cache_cacheableInterface
|
class media_Permalink_Adapter implements media_Permalink_Interface, cache_cacheableInterface
|
||||||
{
|
{
|
||||||
@@ -327,7 +328,7 @@ class media_Permalink_Adapter implements media_Permalink_Interface, cache_cachea
|
|||||||
|
|
||||||
$params = [
|
$params = [
|
||||||
':subdef_id' => $media_subdef->get_subdef_id()
|
':subdef_id' => $media_subdef->get_subdef_id()
|
||||||
, ':token' => $app['random.medium']->generateString(64, \random::LETTERS_AND_NUMBERS)
|
, ':token' => $app['random.medium']->generateString(64, TokenManipulator::LETTERS_AND_NUMBERS)
|
||||||
, ':activated' => '1'
|
, ':activated' => '1'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -58,7 +58,7 @@ class patch_390alpha14a extends patchAbstract
|
|||||||
{
|
{
|
||||||
$app['conf']->remove(['main', 'api-timers']);
|
$app['conf']->remove(['main', 'api-timers']);
|
||||||
|
|
||||||
if ($this->tableHasField($appbox, 'api_logs', 'api_log_ressource')) {
|
if ($this->tableHasField($app['EM'], 'api_logs', 'api_log_ressource')) {
|
||||||
$sql = 'UPDATE api_logs SET api_log_resource = api_log_ressource';
|
$sql = 'UPDATE api_logs SET api_log_resource = api_log_ressource';
|
||||||
$app['phraseanet.appbox']->get_connection()->executeUpdate($sql);
|
$app['phraseanet.appbox']->get_connection()->executeUpdate($sql);
|
||||||
}
|
}
|
||||||
|
70
lib/classes/patch/390alpha15a.php
Normal file
70
lib/classes/patch/390alpha15a.php
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Phraseanet
|
||||||
|
*
|
||||||
|
* (c) 2005-2014 Alchemy
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Alchemy\Phrasea\Application;
|
||||||
|
|
||||||
|
class patch_390alpha15a extends patchAbstract
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
private $release = '3.9.0-alpha.15';
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
private $concern = [base::APPLICATION_BOX];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function get_release()
|
||||||
|
{
|
||||||
|
return $this->release;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function require_all_upgrades()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function concern()
|
||||||
|
{
|
||||||
|
return $this->concern;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getDoctrineMigrations()
|
||||||
|
{
|
||||||
|
return ['token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function apply(base $appbox, Application $app)
|
||||||
|
{
|
||||||
|
if (!$this->tableExists($app['EM'], 'tokens_backup')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = 'INSERT INTO Tokens
|
||||||
|
(value, user_id, type, data, created, updated, expiration)
|
||||||
|
(SELECT value, usr_id, type, datas, created_on, created_on, expire_on FROM tokens_backup)';
|
||||||
|
$appbox->get_connection()->exec($sql);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
use Doctrine\ORM\NoResultException;
|
use Doctrine\ORM\NoResultException;
|
||||||
use Doctrine\ORM\EntityManager;
|
use Doctrine\ORM\EntityManager;
|
||||||
|
use Doctrine\ORM\Query\ResultSetMapping;
|
||||||
|
|
||||||
abstract class patchAbstract implements patchInterface
|
abstract class patchAbstract implements patchInterface
|
||||||
{
|
{
|
||||||
@@ -26,22 +27,21 @@ abstract class patchAbstract implements patchInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function tableExists(base $base, $tableName)
|
protected function tableExists(EntityManager $em, $tableName)
|
||||||
{
|
{
|
||||||
return $base
|
return (Boolean) $em->createNativeQuery(
|
||||||
->get_connection()
|
'SHOW TABLE STATUS WHERE Name="'.$tableName.'" COLLATE utf8_bin ', (new ResultSetMapping())->addScalarResult('Name', 'Name')
|
||||||
->getSchemaManager()
|
)->getOneOrNullResult();
|
||||||
->tablesExist([$tableName]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function tableHasField(base $base, $tableName, $fieldName)
|
protected function tableHasField(EntityManager $em, $tableName, $fieldName)
|
||||||
{
|
{
|
||||||
if (!$this->tableExists($base, $tableName)) {
|
if (!$this->tableExists($em, $tableName)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $base
|
return $em
|
||||||
->get_connection()
|
->getConnection()
|
||||||
->getSchemaManager()
|
->getSchemaManager()
|
||||||
->listTableDetails($tableName)
|
->listTableDetails($tableName)
|
||||||
->hasColumn($fieldName);
|
->hasColumn($fieldName);
|
||||||
|
@@ -10,31 +10,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use Alchemy\Phrasea\Application;
|
use Alchemy\Phrasea\Application;
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|
||||||
|
|
||||||
class random
|
class random
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
const NUMBERS = "0123456789";
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
const LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
const LETTERS_AND_NUMBERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
||||||
const TYPE_FEED_ENTRY = 'FEED_ENTRY';
|
|
||||||
const TYPE_PASSWORD = 'password';
|
|
||||||
const TYPE_DOWNLOAD = 'download';
|
|
||||||
const TYPE_MAIL_DOWNLOAD = 'mail-download';
|
|
||||||
const TYPE_EMAIL = 'email';
|
|
||||||
const TYPE_VIEW = 'view';
|
|
||||||
const TYPE_VALIDATE = 'validate';
|
|
||||||
const TYPE_RSS = 'rss';
|
|
||||||
|
|
||||||
private $app;
|
private $app;
|
||||||
|
|
||||||
public function __construct(Application $app)
|
public function __construct(Application $app)
|
||||||
@@ -82,162 +60,4 @@ class random
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param string $type
|
|
||||||
* @param int $usr
|
|
||||||
* @param DateTime $end_date
|
|
||||||
* @param mixed content $datas
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function getUrlToken($type, $usr, DateTime $end_date = null, $datas = '')
|
|
||||||
{
|
|
||||||
$this->cleanTokens();
|
|
||||||
$conn = $this->app['phraseanet.appbox']->get_connection();
|
|
||||||
$token = $test = false;
|
|
||||||
|
|
||||||
switch ($type) {
|
|
||||||
case self::TYPE_DOWNLOAD:
|
|
||||||
case self::TYPE_MAIL_DOWNLOAD:
|
|
||||||
case self::TYPE_EMAIL:
|
|
||||||
case self::TYPE_PASSWORD:
|
|
||||||
case self::TYPE_VALIDATE:
|
|
||||||
case self::TYPE_VIEW:
|
|
||||||
case self::TYPE_RSS:
|
|
||||||
case self::TYPE_FEED_ENTRY:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Exception_InvalidArgument();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$n = 1;
|
|
||||||
|
|
||||||
$sql = 'SELECT id FROM tokens WHERE value = :test ';
|
|
||||||
$stmt = $conn->prepare($sql);
|
|
||||||
while ($n < 100) {
|
|
||||||
$test = $this->app['random.medium']->generateString(16, self::LETTERS_AND_NUMBERS);
|
|
||||||
$stmt->execute([':test' => $test]);
|
|
||||||
if ($stmt->rowCount() === 0) {
|
|
||||||
$token = $test;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$n ++;
|
|
||||||
}
|
|
||||||
$stmt->closeCursor();
|
|
||||||
|
|
||||||
if ($token) {
|
|
||||||
$sql = 'INSERT INTO tokens (id, value, type, usr_id, created_on, expire_on, datas)
|
|
||||||
VALUES (null, :token, :type, :usr, NOW(), :end_date, :datas)';
|
|
||||||
$stmt = $conn->prepare($sql);
|
|
||||||
|
|
||||||
$params = [
|
|
||||||
':token' => $token
|
|
||||||
, ':type' => $type
|
|
||||||
, ':usr' => ($usr ? $usr : '-1')
|
|
||||||
, ':end_date' => ($end_date instanceof DateTime ? $end_date->format(DATE_ISO8601) : null)
|
|
||||||
, ':datas' => ((trim($datas) != '') ? $datas : null)
|
|
||||||
];
|
|
||||||
$stmt->execute($params);
|
|
||||||
$stmt->closeCursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function removeToken($token)
|
|
||||||
{
|
|
||||||
$this->cleanTokens();
|
|
||||||
|
|
||||||
try {
|
|
||||||
$conn = $this->app['phraseanet.appbox']->get_connection();
|
|
||||||
$sql = 'DELETE FROM tokens WHERE value = :token';
|
|
||||||
$stmt = $conn->prepare($sql);
|
|
||||||
$stmt->execute([':token' => $token]);
|
|
||||||
$stmt->closeCursor();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updateToken($token, $datas)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$conn = $this->app['phraseanet.appbox']->get_connection();
|
|
||||||
|
|
||||||
$sql = 'UPDATE tokens SET datas = :datas
|
|
||||||
WHERE value = :token';
|
|
||||||
|
|
||||||
$stmt = $conn->prepare($sql);
|
|
||||||
$stmt->execute([':datas' => $datas, ':token' => $token]);
|
|
||||||
$stmt->closeCursor();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function helloToken($token)
|
|
||||||
{
|
|
||||||
$this->cleanTokens();
|
|
||||||
|
|
||||||
$conn = $this->app['phraseanet.appbox']->get_connection();
|
|
||||||
$sql = 'SELECT * FROM tokens
|
|
||||||
WHERE value = :token
|
|
||||||
AND (expire_on > NOW() OR expire_on IS NULL)';
|
|
||||||
$stmt = $conn->prepare($sql);
|
|
||||||
$stmt->execute([':token' => $token]);
|
|
||||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
||||||
$stmt->closeCursor();
|
|
||||||
|
|
||||||
if ( ! $row)
|
|
||||||
throw new NotFoundHttpException('Token not found');
|
|
||||||
|
|
||||||
return $row;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the validation token for one user and one validation basket
|
|
||||||
*
|
|
||||||
* @param integer $userId
|
|
||||||
* @param integer $basketId
|
|
||||||
*
|
|
||||||
* @return string The token
|
|
||||||
*
|
|
||||||
* @throws NotFoundHttpException
|
|
||||||
*/
|
|
||||||
public function getValidationToken($userId, $basketId)
|
|
||||||
{
|
|
||||||
$conn = $this->app['phraseanet.appbox']->get_connection();
|
|
||||||
$sql = '
|
|
||||||
SELECT value FROM tokens
|
|
||||||
WHERE type = :type
|
|
||||||
AND usr_id = :usr_id
|
|
||||||
AND datas = :basket_id
|
|
||||||
AND (expire_on > NOW() OR expire_on IS NULL)';
|
|
||||||
|
|
||||||
$stmt = $conn->prepare($sql);
|
|
||||||
$stmt->execute([
|
|
||||||
':type' => self::TYPE_VALIDATE,
|
|
||||||
':usr_id' => (int) $userId,
|
|
||||||
':basket_id' => (int) $basketId,
|
|
||||||
]);
|
|
||||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
||||||
$stmt->closeCursor();
|
|
||||||
|
|
||||||
if (! $row) {
|
|
||||||
throw new NotFoundHttpException('Token not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $row['value'];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
use Alchemy\Phrasea\Application;
|
use Alchemy\Phrasea\Application;
|
||||||
use Alchemy\Phrasea\Model\Serializer\CaptionSerializer;
|
use Alchemy\Phrasea\Model\Serializer\CaptionSerializer;
|
||||||
|
use Alchemy\Phrasea\Model\Entities\Token;
|
||||||
use Alchemy\Phrasea\Model\Entities\User;
|
use Alchemy\Phrasea\Model\Entities\User;
|
||||||
use Symfony\Component\Filesystem\Filesystem;
|
use Symfony\Component\Filesystem\Filesystem;
|
||||||
|
|
||||||
@@ -693,7 +694,7 @@ class set_export extends set_abstract
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function build_zip(Application $app, $token, Array $list, $zipFile)
|
public static function build_zip(Application $app, Token $token, Array $list, $zipFile)
|
||||||
{
|
{
|
||||||
if (isset($list['complete']) && $list['complete'] === true) {
|
if (isset($list['complete']) && $list['complete'] === true) {
|
||||||
return;
|
return;
|
||||||
@@ -703,7 +704,8 @@ class set_export extends set_abstract
|
|||||||
|
|
||||||
$list['complete'] = false;
|
$list['complete'] = false;
|
||||||
|
|
||||||
$app['tokens']->updateToken($token, serialize($list));
|
$token->setData(serialize($list));
|
||||||
|
$app['manipulator.token']->update($token);
|
||||||
|
|
||||||
$toRemove = [];
|
$toRemove = [];
|
||||||
$archiveFiles = [];
|
$archiveFiles = [];
|
||||||
@@ -734,7 +736,8 @@ class set_export extends set_abstract
|
|||||||
|
|
||||||
$list['complete'] = true;
|
$list['complete'] = true;
|
||||||
|
|
||||||
$app['tokens']->updateToken($token, serialize($list));
|
$token->setData(serialize($list));
|
||||||
|
$app['manipulator.token']->update($token);
|
||||||
|
|
||||||
$app['filesystem']->remove($toRemove);
|
$app['filesystem']->remove($toRemove);
|
||||||
$app['filesystem']->chmod($zipFile, 0760);
|
$app['filesystem']->chmod($zipFile, 0760);
|
||||||
|
@@ -2124,85 +2124,6 @@
|
|||||||
</defaults>
|
</defaults>
|
||||||
<engine>InnoDB</engine>
|
<engine>InnoDB</engine>
|
||||||
</table>
|
</table>
|
||||||
<table name="tokens">
|
|
||||||
<fields>
|
|
||||||
<field>
|
|
||||||
<name>id</name>
|
|
||||||
<type>int(11) unsigned</type>
|
|
||||||
<null></null>
|
|
||||||
<extra>auto_increment</extra>
|
|
||||||
</field>
|
|
||||||
<field>
|
|
||||||
<name>value</name>
|
|
||||||
<type>char(16)</type>
|
|
||||||
<null></null>
|
|
||||||
<extra></extra>
|
|
||||||
<collation>ascii_bin</collation>
|
|
||||||
</field>
|
|
||||||
<field>
|
|
||||||
<name>type</name>
|
|
||||||
<type>enum('FEED_ENTRY', 'view','validate','password','rss','email','download')</type>
|
|
||||||
<null></null>
|
|
||||||
<extra></extra>
|
|
||||||
<collation>ascii_bin</collation>
|
|
||||||
</field>
|
|
||||||
<field>
|
|
||||||
<name>usr_id</name>
|
|
||||||
<type>int(11) unsigned</type>
|
|
||||||
<null></null>
|
|
||||||
<extra></extra>
|
|
||||||
</field>
|
|
||||||
<field>
|
|
||||||
<name>datas</name>
|
|
||||||
<type>longtext</type>
|
|
||||||
<null>YES</null>
|
|
||||||
<extra></extra>
|
|
||||||
</field>
|
|
||||||
<field>
|
|
||||||
<name>created_on</name>
|
|
||||||
<type>datetime</type>
|
|
||||||
<null></null>
|
|
||||||
<extra></extra>
|
|
||||||
</field>
|
|
||||||
<field>
|
|
||||||
<name>expire_on</name>
|
|
||||||
<type>datetime</type>
|
|
||||||
<null>YES</null>
|
|
||||||
<extra></extra>
|
|
||||||
</field>
|
|
||||||
</fields>
|
|
||||||
<indexes>
|
|
||||||
<index>
|
|
||||||
<name>PRIMARY</name>
|
|
||||||
<type>PRIMARY</type>
|
|
||||||
<fields>
|
|
||||||
<field>id</field>
|
|
||||||
</fields>
|
|
||||||
</index>
|
|
||||||
<index>
|
|
||||||
<name>value</name>
|
|
||||||
<type>UNIQUE</type>
|
|
||||||
<fields>
|
|
||||||
<field>value</field>
|
|
||||||
</fields>
|
|
||||||
</index>
|
|
||||||
<index>
|
|
||||||
<name>expire</name>
|
|
||||||
<type>INDEX</type>
|
|
||||||
<fields>
|
|
||||||
<field>expire_on</field>
|
|
||||||
</fields>
|
|
||||||
</index>
|
|
||||||
<index>
|
|
||||||
<name>type</name>
|
|
||||||
<type>INDEX</type>
|
|
||||||
<fields>
|
|
||||||
<field>type</field>
|
|
||||||
</fields>
|
|
||||||
</index>
|
|
||||||
</indexes>
|
|
||||||
<engine>InnoDB</engine>
|
|
||||||
</table>
|
|
||||||
</tables>
|
</tables>
|
||||||
</appbox>
|
</appbox>
|
||||||
<databox>
|
<databox>
|
||||||
|
@@ -57,3 +57,6 @@ migrations:
|
|||||||
migration18:
|
migration18:
|
||||||
version: registration
|
version: registration
|
||||||
class: Alchemy\Phrasea\Setup\DoctrineMigrations\RegistrationMigration
|
class: Alchemy\Phrasea\Setup\DoctrineMigrations\RegistrationMigration
|
||||||
|
migration19:
|
||||||
|
version: token
|
||||||
|
class: Alchemy\Phrasea\Setup\DoctrineMigrations\TokenMigration
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% elseif list['complete'] is defined and list['complete'] %}
|
{% elseif list['complete'] is defined and list['complete'] %}
|
||||||
<div class="alert alert-success">
|
<div class="alert alert-success">
|
||||||
{% set url = path('document_download', {'token': token}) %}
|
{% set url = path('document_download', {'token': token.getValue()}) %}
|
||||||
{% set before_link = '<a href="' ~ url ~ '" target="_self">' %}
|
{% set before_link = '<a href="' ~ url ~ '" target="_self">' %}
|
||||||
{% set after_link = '</a>' %}
|
{% set after_link = '</a>' %}
|
||||||
{% trans with {'%before_link%' : before_link, '%after_link%' : after_link} %}Your documents are ready. If the download does not start, %before_link%click here%after_link%{% endtrans %}
|
{% trans with {'%before_link%' : before_link, '%after_link%' : after_link} %}Your documents are ready. If the download does not start, %before_link%click here%after_link%{% endtrans %}
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="display:none">
|
<div style="display:none">
|
||||||
<form name="download" action="{{ path('document_download', {'token': token}) }}" method="post" target="file_frame">
|
<form name="download" action="{{ path('document_download', {'token': token.getValue()}) }}" method="post" target="file_frame">
|
||||||
{% if anonymous %}
|
{% if anonymous %}
|
||||||
<input type="hidden" name="anonymous" value="1" />
|
<input type="hidden" name="anonymous" value="1" />
|
||||||
{% endif%}
|
{% endif%}
|
||||||
@@ -105,7 +105,7 @@
|
|||||||
{% set time = time < 1 ? 2 : (time > 10 ? 10 : time) %}
|
{% set time = time < 1 ? 2 : (time > 10 ? 10 : time) %}
|
||||||
|
|
||||||
{% if list['complete'] is not defined %} {# Zip not done #}
|
{% if list['complete'] is not defined %} {# Zip not done #}
|
||||||
$.post("{{ path('execute_download', {'token': token}) }}", function(data){
|
$.post("{{ path('execute_download', {'token': token.getValue()}) }}", function(data){
|
||||||
var data = $.parseJSON(data);
|
var data = $.parseJSON(data);
|
||||||
if(data.success) {
|
if(data.success) {
|
||||||
$('form[name=download]').submit();
|
$('form[name=download]').submit();
|
||||||
|
@@ -49,9 +49,9 @@ class LightboxTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
$this->logout(self::$DI['app']);
|
$this->logout(self::$DI['app']);
|
||||||
|
|
||||||
$Basket = self::$DI['app']['EM']->find('Phraseanet:Basket', 1);
|
$Basket = self::$DI['app']['EM']->find('Phraseanet:Basket', 1);
|
||||||
$token = self::$DI['app']['tokens']->getUrlToken(\random::TYPE_VIEW, self::$DI['user_alt2']->getId(), null, $Basket->getId());
|
$token = self::$DI['app']['manipulator.token']->createBasketAccessToken($Basket, self::$DI['user_alt2']);
|
||||||
|
|
||||||
self::$DI['client']->request('GET', '/lightbox/?LOG='.$token);
|
self::$DI['client']->request('GET', '/lightbox/?LOG='.$token->getValue());
|
||||||
|
|
||||||
$this->assertTrue(self::$DI['client']->getResponse()->isRedirect());
|
$this->assertTrue(self::$DI['client']->getResponse()->isRedirect());
|
||||||
$this->assertRegExp('/\/lightbox\/validate\/\d+\//', self::$DI['client']->getResponse()->headers->get('location'));
|
$this->assertRegExp('/\/lightbox\/validate\/\d+\//', self::$DI['client']->getResponse()->headers->get('location'));
|
||||||
|
@@ -1,31 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Alchemy\Tests\Phrasea\Authentication\Token;
|
|
||||||
|
|
||||||
use Alchemy\Phrasea\Authentication\Token\TokenValidator;
|
|
||||||
|
|
||||||
class TokenValidatorTest extends \PhraseanetTestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @covers Alchemy\Phrasea\Authentication\TokenValidator::isValid
|
|
||||||
*/
|
|
||||||
public function testValidTokenIsValid()
|
|
||||||
{
|
|
||||||
$usr_id = 42;
|
|
||||||
$token = self::$DI['app']['tokens']->getUrlToken(\random::TYPE_VALIDATE, $usr_id);
|
|
||||||
|
|
||||||
$validator = new TokenValidator(self::$DI['app']['tokens']);
|
|
||||||
$this->assertEquals($usr_id, $validator->isValid($token));
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @covers Alchemy\Phrasea\Authentication\TokenValidator::isValid
|
|
||||||
*/
|
|
||||||
public function testInvalidTokenIsNotValid()
|
|
||||||
{
|
|
||||||
$usr_id = 42;
|
|
||||||
$token = self::$DI['app']['tokens']->getUrlToken(\random::TYPE_VALIDATE, $usr_id, new \DateTime('-2 hours'));
|
|
||||||
|
|
||||||
$validator = new TokenValidator(self::$DI['app']['tokens']);
|
|
||||||
$this->assertFalse($validator->isValid($token));
|
|
||||||
}
|
|
||||||
}
|
|
@@ -37,7 +37,7 @@ class DoDownloadTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
$url = sprintf('/download/%s/prepare/', $token);
|
$url = sprintf('/download/%s/prepare/', $token->getValue());
|
||||||
self::$DI['client']->request('GET', $url);
|
self::$DI['client']->request('GET', $url);
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
$this->assertTrue($response->isOk());
|
$this->assertTrue($response->isOk());
|
||||||
@@ -61,7 +61,7 @@ class DoDownloadTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
public function testPrepareDownloadInvalidData()
|
public function testPrepareDownloadInvalidData()
|
||||||
{
|
{
|
||||||
$token = $this->getToken(['bad_string' => base64_decode(serialize(['fail']))]);
|
$token = $this->getToken(['bad_string' => base64_decode(serialize(['fail']))]);
|
||||||
self::$DI['client']->request('GET', sprintf('/download/%s/prepare/', $token));
|
self::$DI['client']->request('GET', sprintf('/download/%s/prepare/', $token->getValue()));
|
||||||
|
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
$this->assertEquals(500, $response->getStatusCode());
|
$this->assertEquals(500, $response->getStatusCode());
|
||||||
@@ -101,7 +101,7 @@ class DoDownloadTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$url = sprintf('/download/%s/get/', $token);
|
$url = sprintf('/download/%s/get/', $token->getValue());
|
||||||
self::$DI['client']->request('POST', $url);
|
self::$DI['client']->request('POST', $url);
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
$this->assertTrue($response->isOk());
|
$this->assertTrue($response->isOk());
|
||||||
@@ -165,18 +165,16 @@ class DoDownloadTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
];
|
];
|
||||||
|
|
||||||
$token = $this->getToken($list);
|
$token = $this->getToken($list);
|
||||||
// Get token
|
|
||||||
$datas = self::$DI['app']['tokens']->helloToken($token);
|
|
||||||
// Build zip
|
// Build zip
|
||||||
\set_export::build_zip(
|
\set_export::build_zip(
|
||||||
self::$DI['app'],
|
self::$DI['app'],
|
||||||
$token,
|
$token,
|
||||||
$list,
|
$list,
|
||||||
sprintf('%s/../../../../../../tmp/download/%s.zip', __DIR__, $datas['value']) // Dest file
|
sprintf('%s/../../../../../../tmp/download/%s.zip', __DIR__, $token->getValue()) // Dest file
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check response
|
// Check response
|
||||||
$url = sprintf('/download/%s/get/', $token);
|
$url = sprintf('/download/%s/get/', $token->getValue());
|
||||||
self::$DI['client']->request('POST', $url);
|
self::$DI['client']->request('POST', $url);
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
$this->assertTrue($response->isOk());
|
$this->assertTrue($response->isOk());
|
||||||
@@ -216,7 +214,7 @@ class DoDownloadTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
$url = sprintf('/download/%s/get/', $token);
|
$url = sprintf('/download/%s/get/', $token->getValue());
|
||||||
self::$DI['client']->request('POST', $url);
|
self::$DI['client']->request('POST', $url);
|
||||||
|
|
||||||
$this->assertNotFoundResponse(self::$DI['client']->getResponse());
|
$this->assertNotFoundResponse(self::$DI['client']->getResponse());
|
||||||
@@ -239,7 +237,7 @@ class DoDownloadTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
public function testDocumentsDownloadInvalidData()
|
public function testDocumentsDownloadInvalidData()
|
||||||
{
|
{
|
||||||
$token = $this->getToken(['bad_string' => base64_decode(serialize(['fail']))]);
|
$token = $this->getToken(['bad_string' => base64_decode(serialize(['fail']))]);
|
||||||
self::$DI['client']->request('POST', sprintf('/download/%s/get/', $token));
|
self::$DI['client']->request('POST', sprintf('/download/%s/get/', $token->getValue()));
|
||||||
|
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
$this->assertEquals(500, $response->getStatusCode());
|
$this->assertEquals(500, $response->getStatusCode());
|
||||||
@@ -251,8 +249,11 @@ class DoDownloadTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
*/
|
*/
|
||||||
public function testExecuteDownloadInvalidData()
|
public function testExecuteDownloadInvalidData()
|
||||||
{
|
{
|
||||||
$token = $this->getToken(['bad_string' => base64_decode(serialize(['fail']))]);
|
$token = self::$DI['app']['manipulator.token']->createDownloadToken(
|
||||||
$url = sprintf('/download/%s/execute/', $token);
|
self::$DI['user'],
|
||||||
|
base64_decode(serialize(['fail']))
|
||||||
|
);
|
||||||
|
$url = sprintf('/download/%s/execute/', $token->getValue());
|
||||||
self::$DI['client']->request('POST', $url);
|
self::$DI['client']->request('POST', $url);
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
$datas = (array) json_decode($response->getContent());
|
$datas = (array) json_decode($response->getContent());
|
||||||
@@ -268,7 +269,7 @@ class DoDownloadTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
{
|
{
|
||||||
$token = 'ABCDEFGHJaajKISU';
|
$token = 'ABCDEFGHJaajKISU';
|
||||||
$url = sprintf('/download/%s/execute/', $token);
|
$url = sprintf('/download/%s/execute/', $token);
|
||||||
self::$DI['client']->request('POST', $url);
|
self::$DI['client']->request('POST', $url, [], [], ["HTTP_ACCEPT" => "application/json"]);
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
$datas = (array) json_decode($response->getContent());
|
$datas = (array) json_decode($response->getContent());
|
||||||
$this->assertArrayHasKey('success', $datas);
|
$this->assertArrayHasKey('success', $datas);
|
||||||
@@ -329,7 +330,7 @@ class DoDownloadTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
|
|
||||||
$token = $this->getToken($list);
|
$token = $this->getToken($list);
|
||||||
|
|
||||||
$url = sprintf('/download/%s/execute/', $token);
|
$url = sprintf('/download/%s/execute/', $token->getValue());
|
||||||
self::$DI['client']->request('POST', $url);
|
self::$DI['client']->request('POST', $url);
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
$datas = (array) json_decode($response->getContent());
|
$datas = (array) json_decode($response->getContent());
|
||||||
@@ -340,10 +341,8 @@ class DoDownloadTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
|
|
||||||
private function getToken($datas = [])
|
private function getToken($datas = [])
|
||||||
{
|
{
|
||||||
return self::$DI['app']['tokens']->getUrlToken(
|
return self::$DI['app']['manipulator.token']->createDownloadToken(
|
||||||
\random::TYPE_DOWNLOAD,
|
self::$DI['user'],
|
||||||
self::$DI['user']->getId(),
|
|
||||||
new \DateTime('+10 seconds'), // Token lifetime
|
|
||||||
serialize($datas)
|
serialize($datas)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -32,7 +32,7 @@ class DownloadTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
|
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
$this->assertTrue($response->isRedirect());
|
$this->assertTrue($response->isRedirect());
|
||||||
$this->assertRegExp('#/download/[a-zA-Z0-9\.\/]{8,16}/#', $response->headers->get('location'));
|
$this->assertRegExp('#/download/[a-zA-Z0-9]{8,32}/#', $response->headers->get('location'));
|
||||||
unset($response, $eventManagerStub);
|
unset($response, $eventManagerStub);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ class DownloadTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
|
|
||||||
self::$DI['app']['events-manager'] = $eventManagerStub;
|
self::$DI['app']['events-manager'] = $eventManagerStub;
|
||||||
|
|
||||||
self::$DI['app']['authentication']->setUser($this->createUserMock());
|
self::$DI['app']['authentication']->setUser(self::$DI['user']);
|
||||||
|
|
||||||
$stubbedACL = $this->getMockBuilder('\ACL')
|
$stubbedACL = $this->getMockBuilder('\ACL')
|
||||||
->disableOriginalConstructor()
|
->disableOriginalConstructor()
|
||||||
@@ -92,7 +92,7 @@ class DownloadTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
|
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
$this->assertTrue($response->isRedirect());
|
$this->assertTrue($response->isRedirect());
|
||||||
$this->assertRegExp('#/download/[a-zA-Z0-9\.\/]{8,16}/#', $response->headers->get('location'));
|
$this->assertRegExp('#/download/[a-zA-Z0-9]{8,32}/#', $response->headers->get('location'));
|
||||||
unset($response, $eventManagerStub);
|
unset($response, $eventManagerStub);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ class DownloadTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
|
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
$this->assertTrue($response->isRedirect());
|
$this->assertTrue($response->isRedirect());
|
||||||
$this->assertRegExp('#/download/[a-zA-Z0-9\.\/]{8,16}/#', $response->headers->get('location'));
|
$this->assertRegExp('#/download/[a-zA-Z0-9]{8,32}/#', $response->headers->get('location'));
|
||||||
unset($response, $eventManagerStub);
|
unset($response, $eventManagerStub);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ class DownloadTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
|
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
$this->assertTrue($response->isRedirect());
|
$this->assertTrue($response->isRedirect());
|
||||||
$this->assertRegExp('#/download/[a-zA-Z0-9\.\/]{8,16}/#', $response->headers->get('location'));
|
$this->assertRegExp('#/download/[a-zA-Z0-9]{8,32}/#', $response->headers->get('location'));
|
||||||
unset($response, $eventManagerStub);
|
unset($response, $eventManagerStub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -104,19 +104,16 @@ class AccountTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
*/
|
*/
|
||||||
public function testGetResetMailWithToken()
|
public function testGetResetMailWithToken()
|
||||||
{
|
{
|
||||||
$token = self::$DI['app']['tokens']->getUrlToken(\random::TYPE_EMAIL, self::$DI['user']->getId(), null, 'new_email@email.com');
|
$tokenValue = self::$DI['app']['manipulator.token']->createResetEmailToken(self::$DI['user'], 'new_email@email.com')->getValue();
|
||||||
$crawler = self::$DI['client']->request('GET', '/account/reset-email/', ['token' => $token]);
|
$crawler = self::$DI['client']->request('GET', '/account/reset-email/', ['token' => $tokenValue]);
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
$this->assertTrue($response->isRedirect());
|
$this->assertTrue($response->isRedirect());
|
||||||
$this->assertEquals('/account/', $response->headers->get('location'));
|
$this->assertEquals('/account/', $response->headers->get('location'));
|
||||||
|
|
||||||
$this->assertEquals('new_email@email.com', self::$DI['user']->getEmail());
|
$this->assertEquals('new_email@email.com', self::$DI['user']->getEmail());
|
||||||
self::$DI['user']->setEmail('noone@example.com');
|
self::$DI['user']->setEmail('noone@example.com');
|
||||||
try {
|
if (null !== self::$DI['app']['repo.tokens']->find($tokenValue)) {
|
||||||
self::$DI['app']['tokens']->helloToken($token);
|
|
||||||
$this->fail('Token has not been removed');
|
$this->fail('Token has not been removed');
|
||||||
} catch (NotFoundHttpException $e) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->assertFlashMessagePopulated(self::$DI['app'], 'success', 1);
|
$this->assertFlashMessagePopulated(self::$DI['app'], 'success', 1);
|
||||||
|
@@ -11,6 +11,7 @@ use Alchemy\Phrasea\Exception\InvalidArgumentException;
|
|||||||
use Alchemy\Phrasea\Authentication\ProvidersCollection;
|
use Alchemy\Phrasea\Authentication\ProvidersCollection;
|
||||||
use Alchemy\Phrasea\Model\Entities\Registration;
|
use Alchemy\Phrasea\Model\Entities\Registration;
|
||||||
use Alchemy\Phrasea\Model\Entities\User;
|
use Alchemy\Phrasea\Model\Entities\User;
|
||||||
|
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||||
use RandomLib\Factory;
|
use RandomLib\Factory;
|
||||||
use Symfony\Component\HttpKernel\Client;
|
use Symfony\Component\HttpKernel\Client;
|
||||||
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
||||||
@@ -170,9 +171,12 @@ class LoginTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
{
|
{
|
||||||
$this->logout(self::$DI['app']);
|
$this->logout(self::$DI['app']);
|
||||||
$email = $this->generateEmail();
|
$email = $this->generateEmail();
|
||||||
$token = self::$DI['app']['tokens']->getUrlToken(\random::TYPE_EMAIL, 0, null, $email);
|
$token = self::$DI['app']['manipulator.token']->createResetEmailToken(self::$DI['user'], $email);
|
||||||
|
$tokenValue = $token->getValue();
|
||||||
|
self::$DI['app']['EM']->remove($token);
|
||||||
|
self::$DI['app']['EM']->flush();
|
||||||
self::$DI['client']->request('GET', '/login/register-confirm/', [
|
self::$DI['client']->request('GET', '/login/register-confirm/', [
|
||||||
'code' => $token
|
'code' => $tokenValue
|
||||||
]);
|
]);
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
|
|
||||||
@@ -188,11 +192,11 @@ class LoginTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
{
|
{
|
||||||
$this->logout(self::$DI['app']);
|
$this->logout(self::$DI['app']);
|
||||||
$email = $this->generateEmail();
|
$email = $this->generateEmail();
|
||||||
$token = self::$DI['app']['tokens']->getUrlToken(\random::TYPE_EMAIL, self::$DI['user']->getId(), null, $email);
|
$token = self::$DI['app']['manipulator.token']->createResetEmailToken(self::$DI['user'], $email);
|
||||||
|
|
||||||
self::$DI['user']->setMailLocked(false);
|
self::$DI['user']->setMailLocked(false);
|
||||||
|
|
||||||
self::$DI['client']->request('GET', '/login/register-confirm/', ['code' => $token]);
|
self::$DI['client']->request('GET', '/login/register-confirm/', ['code' => $token->getValue()]);
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
|
|
||||||
$this->assertTrue($response->isRedirect());
|
$this->assertTrue($response->isRedirect());
|
||||||
@@ -207,7 +211,7 @@ class LoginTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
|
|
||||||
$this->logout(self::$DI['app']);
|
$this->logout(self::$DI['app']);
|
||||||
$email = $this->generateEmail();
|
$email = $this->generateEmail();
|
||||||
$token = self::$DI['app']['tokens']->getUrlToken(\random::TYPE_EMAIL, self::$DI['user']->getId(), null, $email);
|
$token = self::$DI['app']['manipulator.token']->createResetEmailToken(self::$DI['user'], $email);
|
||||||
|
|
||||||
self::$DI['user']->setMailLocked(true);
|
self::$DI['user']->setMailLocked(true);
|
||||||
$this->deleteRequest();
|
$this->deleteRequest();
|
||||||
@@ -218,7 +222,7 @@ class LoginTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
self::$DI['app']['EM']->persist($registration);
|
self::$DI['app']['EM']->persist($registration);
|
||||||
self::$DI['app']['EM']->flush();
|
self::$DI['app']['EM']->flush();
|
||||||
|
|
||||||
self::$DI['client']->request('GET', '/login/register-confirm/', ['code' => $token]);
|
self::$DI['client']->request('GET', '/login/register-confirm/', ['code' => $token->getValue()]);
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
|
|
||||||
$this->assertTrue($response->isRedirect());
|
$this->assertTrue($response->isRedirect());
|
||||||
@@ -235,13 +239,13 @@ class LoginTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
$this->logout(self::$DI['app']);
|
$this->logout(self::$DI['app']);
|
||||||
$email = $this->generateEmail();
|
$email = $this->generateEmail();
|
||||||
$user = self::$DI['app']['manipulator.user']->createUser('test', 'test', $email);
|
$user = self::$DI['app']['manipulator.user']->createUser('test', 'test', $email);
|
||||||
$token = self::$DI['app']['tokens']->getUrlToken(\random::TYPE_EMAIL, $user->getId(), null, $email);
|
$token = self::$DI['app']['manipulator.token']->createResetEmailToken($user, $email);
|
||||||
|
|
||||||
$user->setMailLocked(true);
|
$user->setMailLocked(true);
|
||||||
|
|
||||||
$this->deleteRequest();
|
$this->deleteRequest();
|
||||||
|
|
||||||
self::$DI['client']->request('GET', '/login/register-confirm/', ['code' => $token]);
|
self::$DI['client']->request('GET', '/login/register-confirm/', ['code' => $token->getValue()]);
|
||||||
$response = self::$DI['client']->getResponse();
|
$response = self::$DI['client']->getResponse();
|
||||||
$this->assertTrue($response->isRedirect());
|
$this->assertTrue($response->isRedirect());
|
||||||
$this->assertFlashMessagePopulated(self::$DI['app'], 'info', 1);
|
$this->assertFlashMessagePopulated(self::$DI['app'], 'info', 1);
|
||||||
@@ -304,9 +308,9 @@ class LoginTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
public function testRenewPasswordBadArguments()
|
public function testRenewPasswordBadArguments()
|
||||||
{
|
{
|
||||||
$this->logout(self::$DI['app']);
|
$this->logout(self::$DI['app']);
|
||||||
$token = self::$DI['app']['tokens']->getUrlToken(\random::TYPE_PASSWORD, self::$DI['user']->getId());
|
$token = self::$DI['app']['manipulator.token']->createResetPasswordToken(self::$DI['user']);
|
||||||
$crawler = self::$DI['client']->request('POST', '/login/renew-password/', [
|
$crawler = self::$DI['client']->request('POST', '/login/renew-password/', [
|
||||||
'token' => $token,
|
'token' => $token->getValue(),
|
||||||
'_token' => 'token',
|
'_token' => 'token',
|
||||||
'password' => ['password' => 'password', 'confirm' => 'not_identical']
|
'password' => ['password' => 'password', 'confirm' => 'not_identical']
|
||||||
]);
|
]);
|
||||||
@@ -376,10 +380,10 @@ class LoginTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
public function testRenewPassword()
|
public function testRenewPassword()
|
||||||
{
|
{
|
||||||
$this->logout(self::$DI['app']);
|
$this->logout(self::$DI['app']);
|
||||||
$token = self::$DI['app']['tokens']->getUrlToken(\random::TYPE_PASSWORD, self::$DI['user']->getId());
|
$token = self::$DI['app']['manipulator.token']->createResetPasswordToken(self::$DI['user']);
|
||||||
|
|
||||||
self::$DI['client']->request('POST', '/login/renew-password/', [
|
self::$DI['client']->request('POST', '/login/renew-password/', [
|
||||||
'token' => $token,
|
'token' => $token->getValue(),
|
||||||
'_token' => 'token',
|
'_token' => 'token',
|
||||||
'password' => ['password' => 'password', 'confirm' => 'password']
|
'password' => ['password' => 'password', 'confirm' => 'password']
|
||||||
]);
|
]);
|
||||||
@@ -400,10 +404,10 @@ class LoginTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
$this->logout(self::$DI['app']);
|
$this->logout(self::$DI['app']);
|
||||||
self::$DI['app']->addFlash($type, $message);
|
self::$DI['app']->addFlash($type, $message);
|
||||||
|
|
||||||
$token = self::$DI['app']['tokens']->getUrlToken(\random::TYPE_PASSWORD, self::$DI['user']->getId());
|
$token = self::$DI['app']['manipulator.token']->createResetPasswordToken(self::$DI['user']);
|
||||||
|
|
||||||
$crawler = self::$DI['client']->request('GET', '/login/renew-password/', [
|
$crawler = self::$DI['client']->request('GET', '/login/renew-password/', [
|
||||||
'token' => $token
|
'token' => $token->getValue()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertTrue(self::$DI['client']->getResponse()->isOk());
|
$this->assertTrue(self::$DI['client']->getResponse()->isOk());
|
||||||
@@ -1794,7 +1798,7 @@ class LoginTest extends \PhraseanetAuthenticatedWebTestCase
|
|||||||
$factory = new Factory();
|
$factory = new Factory();
|
||||||
$generator = $factory->getLowStrengthGenerator();
|
$generator = $factory->getLowStrengthGenerator();
|
||||||
|
|
||||||
return $generator->generateString(8, \random::LETTERS_AND_NUMBERS) . '_email@email.com';
|
return $generator->generateString(8, TokenManipulator::LETTERS_AND_NUMBERS) . '_email@email.com';
|
||||||
}
|
}
|
||||||
|
|
||||||
private function disableTOU()
|
private function disableTOU()
|
||||||
|
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Alchemy\Tests\Phrasea\Core\Middleware;
|
||||||
|
|
||||||
|
use Alchemy\Phrasea\Core\Middleware\TokenMiddlewareProvider;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
class TokenMiddlewareProviderTest extends MiddlewareProviderTestCase
|
||||||
|
{
|
||||||
|
public function provideDescription()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'Alchemy\Phrasea\Core\Middleware\TokenMiddlewareProvider',
|
||||||
|
'middleware.token.converter'
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConverterWithNoParameter()
|
||||||
|
{
|
||||||
|
$this->authenticate(self::$DI['app']);
|
||||||
|
self::$DI['app']->register(new TokenMiddlewareProvider());
|
||||||
|
$request = new Request();
|
||||||
|
call_user_func(self::$DI['app']['middleware.token.converter'], $request, self::$DI['app']);
|
||||||
|
$this->assertNull($request->attributes->get('token'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConverterWithBasketParameter()
|
||||||
|
{
|
||||||
|
$this->authenticate(self::$DI['app']);
|
||||||
|
self::$DI['app']->register(new TokenMiddlewareProvider());
|
||||||
|
$request = new Request();
|
||||||
|
$token = self::$DI['token_1'];
|
||||||
|
$request->attributes->set('token', $token->getValue());
|
||||||
|
call_user_func(self::$DI['app']['middleware.token.converter'], $request, self::$DI['app']);
|
||||||
|
$this->assertSame($token, $request->attributes->get('token'));
|
||||||
|
}
|
||||||
|
}
|
@@ -20,11 +20,6 @@ class AuthenticationManagerServiceProviderTest extends ServiceProviderTestCase
|
|||||||
'authentication',
|
'authentication',
|
||||||
'Alchemy\\Phrasea\\Authentication\\Authenticator',
|
'Alchemy\\Phrasea\\Authentication\\Authenticator',
|
||||||
],
|
],
|
||||||
[
|
|
||||||
'Alchemy\Phrasea\Core\Provider\AuthenticationManagerServiceProvider',
|
|
||||||
'authentication.token-validator',
|
|
||||||
'Alchemy\Phrasea\Authentication\Token\TokenValidator'
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
'Alchemy\Phrasea\Core\Provider\AuthenticationManagerServiceProvider',
|
'Alchemy\Phrasea\Core\Provider\AuthenticationManagerServiceProvider',
|
||||||
'authentication.persistent-manager',
|
'authentication.persistent-manager',
|
||||||
|
@@ -17,6 +17,11 @@ class ConvertersServiceProvider extends ServiceProviderTestCase
|
|||||||
'converter.basket',
|
'converter.basket',
|
||||||
'Alchemy\Phrasea\Controller\Converter\BasketConverter'
|
'Alchemy\Phrasea\Controller\Converter\BasketConverter'
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'Alchemy\Phrasea\Core\Provider\ConvertersServiceProvider',
|
||||||
|
'converter.token',
|
||||||
|
'Alchemy\Phrasea\Controller\Converter\TokenConverter'
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,11 @@ class ManipulatorServiceProviderTest extends ServiceProviderTestCase
|
|||||||
'manipulator.registration',
|
'manipulator.registration',
|
||||||
'Alchemy\Phrasea\Model\Manipulator\RegistrationManipulator'
|
'Alchemy\Phrasea\Model\Manipulator\RegistrationManipulator'
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'Alchemy\Phrasea\Core\Provider\ManipulatorServiceProvider',
|
||||||
|
'manipulator.token',
|
||||||
|
'Alchemy\Phrasea\Model\Manipulator\TokenManipulator'
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,6 +31,7 @@ class RepositoriesServiceProviderTest extends ServiceProviderTestCase
|
|||||||
['Alchemy\Phrasea\Core\Provider\RepositoriesServiceProvider', 'repo.usr-auth-providers', 'Alchemy\Phrasea\Model\Repositories\UsrAuthProviderRepository'],
|
['Alchemy\Phrasea\Core\Provider\RepositoriesServiceProvider', 'repo.usr-auth-providers', 'Alchemy\Phrasea\Model\Repositories\UsrAuthProviderRepository'],
|
||||||
['Alchemy\Phrasea\Core\Provider\RepositoriesServiceProvider', 'repo.ftp-exports', 'Alchemy\Phrasea\Model\Repositories\FtpExportRepository'],
|
['Alchemy\Phrasea\Core\Provider\RepositoriesServiceProvider', 'repo.ftp-exports', 'Alchemy\Phrasea\Model\Repositories\FtpExportRepository'],
|
||||||
['Alchemy\Phrasea\Core\Provider\RepositoriesServiceProvider', 'repo.user-queries', 'Alchemy\Phrasea\Model\Repositories\UserQueryRepository'],
|
['Alchemy\Phrasea\Core\Provider\RepositoriesServiceProvider', 'repo.user-queries', 'Alchemy\Phrasea\Model\Repositories\UserQueryRepository'],
|
||||||
|
['Alchemy\Phrasea\Core\Provider\RepositoriesServiceProvider', 'repo.tokens', 'Alchemy\Phrasea\Model\Repositories\TokenRepository'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,47 +3,51 @@
|
|||||||
namespace Alchemy\Tests\Phrasea\Form\Constraint;
|
namespace Alchemy\Tests\Phrasea\Form\Constraint;
|
||||||
|
|
||||||
use Alchemy\Phrasea\Form\Constraint\PasswordToken;
|
use Alchemy\Phrasea\Form\Constraint\PasswordToken;
|
||||||
|
use Alchemy\Phrasea\Model\Entities\Token;
|
||||||
|
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
|
|
||||||
class PasswordTokenTest extends \PhraseanetTestCase
|
class PasswordTokenTest extends \PhraseanetTestCase
|
||||||
{
|
{
|
||||||
public function testInvalidTokenIsNotValid()
|
public function testInvalidTokenIsNotValid()
|
||||||
{
|
{
|
||||||
$random = $this
|
$repo = $this
|
||||||
->getMockBuilder('random')
|
->getMockBuilder('Doctrine\ORM\EntityRepository')
|
||||||
->disableOriginalConstructor()
|
->disableOriginalConstructor()
|
||||||
->setMethods(['helloToken'])
|
->setMethods(['findValidToken'])
|
||||||
->getMock();
|
->getMock();
|
||||||
|
|
||||||
$token = self::$DI['app']['random.low']->generateString(8);
|
$tokenValue = self::$DI['app']['random.low']->generateString(8);
|
||||||
|
|
||||||
$random
|
$repo
|
||||||
->expects($this->once())
|
->expects($this->once())
|
||||||
->method('helloToken')
|
->method('findValidToken')
|
||||||
->with($token)
|
->with($tokenValue)
|
||||||
->will($this->throwException(new NotFoundHttpException('Token not found')));
|
->will($this->returnValue(null));
|
||||||
|
|
||||||
$constraint = new PasswordToken($random);
|
$constraint = new PasswordToken($repo);
|
||||||
$this->assertFalse($constraint->isValid($token));
|
$this->assertFalse($constraint->isValid($tokenValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testValidTokenIsValid()
|
public function testValidTokenIsValid()
|
||||||
{
|
{
|
||||||
$random = $this
|
$repo = $this
|
||||||
->getMockBuilder('random')
|
->getMockBuilder('Doctrine\ORM\EntityRepository')
|
||||||
->disableOriginalConstructor()
|
->disableOriginalConstructor()
|
||||||
->setMethods(['helloToken'])
|
->setMethods(['findValidToken'])
|
||||||
->getMock();
|
->getMock();
|
||||||
|
|
||||||
$token = self::$DI['app']['random.low']->generateString(8);
|
$tokenValue = self::$DI['app']['random.low']->generateString(8);
|
||||||
|
$token = new Token();
|
||||||
|
$token->setType(TokenManipulator::TYPE_PASSWORD);
|
||||||
|
|
||||||
$random
|
$repo
|
||||||
->expects($this->once())
|
->expects($this->once())
|
||||||
->method('helloToken')
|
->method('findValidToken')
|
||||||
->with($token)
|
->with($tokenValue)
|
||||||
->will($this->returnValue(['usr_id' => mt_rand(), 'type' => \random::TYPE_PASSWORD]));
|
->will($this->returnValue($token));
|
||||||
|
|
||||||
$constraint = new PasswordToken($random);
|
$constraint = new PasswordToken($repo);
|
||||||
$this->assertTrue($constraint->isValid($token));
|
$this->assertTrue($constraint->isValid($tokenValue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,6 @@ class PhraseaRecoverPasswordFormTest extends FormTestCase
|
|||||||
{
|
{
|
||||||
protected function getForm()
|
protected function getForm()
|
||||||
{
|
{
|
||||||
return new PhraseaRecoverPasswordForm(self::$DI['app']['tokens']);
|
return new PhraseaRecoverPasswordForm(self::$DI['app']['repo.tokens']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Alchemy\Tests\Phrasea\Model\Converter;
|
||||||
|
|
||||||
|
use Alchemy\Phrasea\Model\Converter\TokenConverter;
|
||||||
|
|
||||||
|
class TokenConverterTest extends \PhraseanetTestCase
|
||||||
|
{
|
||||||
|
public function testConvert()
|
||||||
|
{
|
||||||
|
$token = self::$DI['token_1'];
|
||||||
|
|
||||||
|
$converter = new TokenConverter(self::$DI['app']['repo.tokens']);
|
||||||
|
$this->assertSame($token, $converter->convert($token->getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
||||||
|
* @expectedExceptionMessage Token is not valid.
|
||||||
|
*/
|
||||||
|
public function testConvertFailure()
|
||||||
|
{
|
||||||
|
$converter = new TokenConverter(self::$DI['app']['repo.tokens']);
|
||||||
|
$converter->convert('prout');
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,185 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Alchemy\Tests\Phrasea\Model\Manipulator;
|
||||||
|
|
||||||
|
use Alchemy\Phrasea\Model\Entities\Token;
|
||||||
|
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||||
|
|
||||||
|
class TokenManipulatorTest extends \PhraseanetTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @dataProvider provideConstructorArguments
|
||||||
|
*/
|
||||||
|
public function testCreate($user, $type, $expiration, $data)
|
||||||
|
{
|
||||||
|
$user = $user ? self::$DI['user'] : null;
|
||||||
|
|
||||||
|
$manipulator = new TokenManipulator(self::$DI['app']['EM'], self::$DI['app']['random.low'], self::$DI['app']['repo.tokens']);
|
||||||
|
$token = $manipulator->create($user, $type, $expiration, $data);
|
||||||
|
|
||||||
|
$this->assertSame($user, $token->getUser());
|
||||||
|
$this->assertSame($type, $token->getType());
|
||||||
|
$this->assertSame($expiration, $token->getExpiration());
|
||||||
|
$this->assertSame($data, $token->getData());
|
||||||
|
|
||||||
|
$this->assertInternalType('string', $token->getValue());
|
||||||
|
$this->assertEquals(32, strlen($token->getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideConstructorArguments()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[true, TokenManipulator::TYPE_RSS, null, null],
|
||||||
|
[false, TokenManipulator::TYPE_RSS, null, null],
|
||||||
|
[false, TokenManipulator::TYPE_RSS, new \DateTime('-1 day'), 'data'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateBasketValidationToken()
|
||||||
|
{
|
||||||
|
$manipulator = new TokenManipulator(self::$DI['app']['EM'], self::$DI['app']['random.low'], self::$DI['app']['repo.tokens']);
|
||||||
|
$token = $manipulator->createBasketValidationToken(self::$DI['basket_4'], self::$DI['user_1']);
|
||||||
|
|
||||||
|
$this->assertSame(self::$DI['basket_4']->getId(), $token->getData());
|
||||||
|
$this->assertSame(self::$DI['user_1'], $token->getUser());
|
||||||
|
$this->assertSame(TokenManipulator::TYPE_VALIDATE, $token->getType());
|
||||||
|
$this->assertDateNear('+10 days', $token->getExpiration());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateBasketValidationTokenWithoutUser()
|
||||||
|
{
|
||||||
|
$manipulator = new TokenManipulator(self::$DI['app']['EM'], self::$DI['app']['random.low'], self::$DI['app']['repo.tokens']);
|
||||||
|
$token = $manipulator->createBasketValidationToken(self::$DI['basket_4']);
|
||||||
|
|
||||||
|
$this->assertSame(self::$DI['basket_4']->getId(), $token->getData());
|
||||||
|
$this->assertSame(self::$DI['basket_4']->getValidation()->getInitiator(), $token->getUser());
|
||||||
|
$this->assertSame(TokenManipulator::TYPE_VALIDATE, $token->getType());
|
||||||
|
$this->assertDateNear('+10 days', $token->getExpiration());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateBasketValidationTokenWithInvalidBasket()
|
||||||
|
{
|
||||||
|
$manipulator = new TokenManipulator(self::$DI['app']['EM'], self::$DI['app']['random.low'], self::$DI['app']['repo.tokens']);
|
||||||
|
$this->setExpectedException('InvalidArgumentException', 'A validation token requires a validation basket.');
|
||||||
|
$manipulator->createBasketValidationToken(self::$DI['basket_1']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateBasketAccessToken()
|
||||||
|
{
|
||||||
|
$manipulator = new TokenManipulator(self::$DI['app']['EM'], self::$DI['app']['random.low'], self::$DI['app']['repo.tokens']);
|
||||||
|
$token = $manipulator->createBasketAccessToken(self::$DI['basket_4'], self::$DI['user']);
|
||||||
|
|
||||||
|
$this->assertSame(self::$DI['basket_4']->getId(), $token->getData());
|
||||||
|
$this->assertSame(self::$DI['user'], $token->getUser());
|
||||||
|
$this->assertSame(TokenManipulator::TYPE_VIEW, $token->getType());
|
||||||
|
$this->assertNull($token->getExpiration());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateFeedEntryToken()
|
||||||
|
{
|
||||||
|
$manipulator = new TokenManipulator(self::$DI['app']['EM'], self::$DI['app']['random.low'], self::$DI['app']['repo.tokens']);
|
||||||
|
$token = $manipulator->createFeedEntryToken(self::$DI['user'], self::$DI['feed_public_entry']);
|
||||||
|
|
||||||
|
$this->assertSame(self::$DI['feed_public_entry']->getId(), $token->getData());
|
||||||
|
$this->assertSame(self::$DI['user'], $token->getUser());
|
||||||
|
$this->assertSame(TokenManipulator::TYPE_FEED_ENTRY, $token->getType());
|
||||||
|
$this->assertNull($token->getExpiration());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateDownloadToken()
|
||||||
|
{
|
||||||
|
$data = serialize(array('some' => 'data'));
|
||||||
|
$manipulator = new TokenManipulator(self::$DI['app']['EM'], self::$DI['app']['random.low'], self::$DI['app']['repo.tokens']);
|
||||||
|
$token = $manipulator->createDownloadToken(self::$DI['user'], $data);
|
||||||
|
|
||||||
|
$this->assertSame($data, $token->getData());
|
||||||
|
$this->assertSame(self::$DI['user'], $token->getUser());
|
||||||
|
$this->assertSame(TokenManipulator::TYPE_DOWNLOAD, $token->getType());
|
||||||
|
$this->assertDateNear('+3 hours', $token->getExpiration());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateEmailExportToken()
|
||||||
|
{
|
||||||
|
$data = serialize(array('some' => 'data'));
|
||||||
|
$manipulator = new TokenManipulator(self::$DI['app']['EM'], self::$DI['app']['random.low'], self::$DI['app']['repo.tokens']);
|
||||||
|
$token = $manipulator->createEmailExportToken($data);
|
||||||
|
|
||||||
|
$this->assertSame($data, $token->getData());
|
||||||
|
$this->assertNull($token->getUser());
|
||||||
|
$this->assertSame(TokenManipulator::TYPE_EMAIL, $token->getType());
|
||||||
|
$this->assertDateNear('+1 day', $token->getExpiration());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateResetEmailToken()
|
||||||
|
{
|
||||||
|
$manipulator = new TokenManipulator(self::$DI['app']['EM'], self::$DI['app']['random.low'], self::$DI['app']['repo.tokens']);
|
||||||
|
$token = $manipulator->createResetEmailToken(self::$DI['user'], 'newemail@phraseanet.com');
|
||||||
|
|
||||||
|
$this->assertSame('newemail@phraseanet.com', $token->getData());
|
||||||
|
$this->assertSame(self::$DI['user'], $token->getUser());
|
||||||
|
$this->assertSame(TokenManipulator::TYPE_EMAIL_RESET, $token->getType());
|
||||||
|
$this->assertDateNear('+1 day', $token->getExpiration());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateAccountUnlockToken()
|
||||||
|
{
|
||||||
|
$manipulator = new TokenManipulator(self::$DI['app']['EM'], self::$DI['app']['random.low'], self::$DI['app']['repo.tokens']);
|
||||||
|
$token = $manipulator->createAccountUnlockToken(self::$DI['user']);
|
||||||
|
|
||||||
|
$this->assertNull($token->getData());
|
||||||
|
$this->assertSame(self::$DI['user'], $token->getUser());
|
||||||
|
$this->assertSame(TokenManipulator::TYPE_ACCOUNT_UNLOCK, $token->getType());
|
||||||
|
$this->assertDateNear('+3 days', $token->getExpiration());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateResetPasswordToken()
|
||||||
|
{
|
||||||
|
$manipulator = new TokenManipulator(self::$DI['app']['EM'], self::$DI['app']['random.low'], self::$DI['app']['repo.tokens']);
|
||||||
|
$token = $manipulator->createResetPasswordToken(self::$DI['user']);
|
||||||
|
|
||||||
|
$this->assertNull($token->getData());
|
||||||
|
$this->assertSame(self::$DI['user'], $token->getUser());
|
||||||
|
$this->assertSame(TokenManipulator::TYPE_PASSWORD, $token->getType());
|
||||||
|
$this->assertDateNear('+1 day', $token->getExpiration());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUpdate()
|
||||||
|
{
|
||||||
|
$em = $this->createEntityManagerMock();
|
||||||
|
$token = new Token();
|
||||||
|
|
||||||
|
$em->expects($this->once())
|
||||||
|
->method('persist')
|
||||||
|
->with($token);
|
||||||
|
$em->expects($this->once())
|
||||||
|
->method('flush');
|
||||||
|
|
||||||
|
$manipulator = new TokenManipulator($em, self::$DI['app']['random.low'], self::$DI['app']['repo.tokens']);
|
||||||
|
$manipulator->update($token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDelete()
|
||||||
|
{
|
||||||
|
$em = $this->createEntityManagerMock();
|
||||||
|
$token = new Token();
|
||||||
|
|
||||||
|
$em->expects($this->once())
|
||||||
|
->method('remove')
|
||||||
|
->with($token);
|
||||||
|
$em->expects($this->once())
|
||||||
|
->method('flush');
|
||||||
|
|
||||||
|
$manipulator = new TokenManipulator($em, self::$DI['app']['random.low'], self::$DI['app']['repo.tokens']);
|
||||||
|
$manipulator->delete($token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRemoveExpiredToken()
|
||||||
|
{
|
||||||
|
$this->assertCount(4, self::$DI['app']['repo.tokens']->findAll());
|
||||||
|
|
||||||
|
$manipulator = new TokenManipulator(self::$DI['app']['EM'], self::$DI['app']['random.low'], self::$DI['app']['repo.tokens']);
|
||||||
|
$manipulator->removeExpiredTokens();
|
||||||
|
|
||||||
|
$this->assertCount(3, self::$DI['app']['repo.tokens']->findAll());
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Alchemy\Tests\Phrasea\Model\Repositories;
|
||||||
|
|
||||||
|
class TokenRepositoryTest extends \PhraseanetTestCase
|
||||||
|
{
|
||||||
|
public function testFindValidToken()
|
||||||
|
{
|
||||||
|
$repo = self::$DI['app']['repo.tokens'];
|
||||||
|
$this->assertSame(self::$DI['token_1'], $repo->findValidToken(self::$DI['token_1']->getValue()));
|
||||||
|
$this->assertSame(self::$DI['token_2'], $repo->findValidToken(self::$DI['token_2']->getValue()));
|
||||||
|
$this->assertNull($repo->findValidToken(self::$DI['token_invalid']->getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFindValidationToken()
|
||||||
|
{
|
||||||
|
$repo = self::$DI['app']['repo.tokens'];
|
||||||
|
$this->assertSame(self::$DI['token_validation'], $repo->findValidationToken(self::$DI['basket_1'], self::$DI['user']));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExpiredTokens()
|
||||||
|
{
|
||||||
|
$repo = self::$DI['app']['repo.tokens'];
|
||||||
|
$tokens = $repo->findExpiredTokens();
|
||||||
|
$this->assertCount(1, $tokens);
|
||||||
|
$this->assertSame(self::$DI['token_invalid'], array_pop($tokens));
|
||||||
|
}
|
||||||
|
}
|
@@ -100,6 +100,58 @@ abstract class PhraseanetTestCase extends WebTestCase
|
|||||||
return new Client($DI['app'], []);
|
return new Client($DI['app'], []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
self::$DI['feed_public'] = self::$DI->share(function ($DI) {
|
||||||
|
return $DI['app']['repo.feeds']->find(self::$fixtureIds['feed']['public']['feed']);
|
||||||
|
});
|
||||||
|
self::$DI['feed_public_entry'] = self::$DI->share(function ($DI) {
|
||||||
|
return $DI['app']['repo.feed-entries']->find(self::$fixtureIds['feed']['public']['entry']);
|
||||||
|
});
|
||||||
|
self::$DI['feed_public_token'] = self::$DI->share(function ($DI) {
|
||||||
|
return $DI['app']['repo.feed-tokens']->find(self::$fixtureIds['feed']['public']['token']);
|
||||||
|
});
|
||||||
|
|
||||||
|
self::$DI['feed_private'] = self::$DI->share(function ($DI) {
|
||||||
|
return $DI['app']['repo.feeds']->find(self::$fixtureIds['feed']['private']['feed']);
|
||||||
|
});
|
||||||
|
self::$DI['feed_private_entry'] = self::$DI->share(function ($DI) {
|
||||||
|
return $DI['app']['repo.feed-entries']->find(self::$fixtureIds['feed']['private']['entry']);
|
||||||
|
});
|
||||||
|
self::$DI['feed_private_token'] = self::$DI->share(function ($DI) {
|
||||||
|
return $DI['app']['repo.feed-tokens']->find(self::$fixtureIds['feed']['private']['token']);
|
||||||
|
});
|
||||||
|
|
||||||
|
self::$DI['basket_1'] = self::$DI->share(function ($DI) {
|
||||||
|
return $DI['app']['repo.baskets']->find(self::$fixtureIds['basket']['basket_1']);
|
||||||
|
});
|
||||||
|
|
||||||
|
self::$DI['basket_2'] = self::$DI->share(function ($DI) {
|
||||||
|
return $DI['app']['repo.baskets']->find(self::$fixtureIds['basket']['basket_2']);
|
||||||
|
});
|
||||||
|
|
||||||
|
self::$DI['basket_3'] = self::$DI->share(function ($DI) {
|
||||||
|
return $DI['app']['repo.baskets']->find(self::$fixtureIds['basket']['basket_3']);
|
||||||
|
});
|
||||||
|
|
||||||
|
self::$DI['basket_4'] = self::$DI->share(function ($DI) {
|
||||||
|
return $DI['app']['repo.baskets']->find(self::$fixtureIds['basket']['basket_4']);
|
||||||
|
});
|
||||||
|
|
||||||
|
self::$DI['token_1'] = self::$DI->share(function ($DI) {
|
||||||
|
return $DI['app']['repo.tokens']->find(self::$fixtureIds['token']['token_1']);
|
||||||
|
});
|
||||||
|
|
||||||
|
self::$DI['token_2'] = self::$DI->share(function ($DI) {
|
||||||
|
return $DI['app']['repo.tokens']->find(self::$fixtureIds['token']['token_2']);
|
||||||
|
});
|
||||||
|
|
||||||
|
self::$DI['token_invalid'] = self::$DI->share(function ($DI) {
|
||||||
|
return $DI['app']['repo.tokens']->find(self::$fixtureIds['token']['token_invalid']);
|
||||||
|
});
|
||||||
|
|
||||||
|
self::$DI['token_validation'] = self::$DI->share(function ($DI) {
|
||||||
|
return $DI['app']['repo.tokens']->find(self::$fixtureIds['token']['token_validation']);
|
||||||
|
});
|
||||||
|
|
||||||
self::$DI['user'] = self::$DI->share(function ($DI) {
|
self::$DI['user'] = self::$DI->share(function ($DI) {
|
||||||
return $DI['app']['repo.users']->find(self::$fixtureIds['user']['test_phpunit']);
|
return $DI['app']['repo.users']->find(self::$fixtureIds['user']['test_phpunit']);
|
||||||
});
|
});
|
||||||
@@ -672,6 +724,14 @@ abstract class PhraseanetTestCase extends WebTestCase
|
|||||||
->getMock();
|
->getMock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function assertDateNear($expected, $tested, $precision = 1)
|
||||||
|
{
|
||||||
|
$tested = $tested instanceof \DateTime ? $tested : new \DateTime($tested);
|
||||||
|
$expected = $expected instanceof \DateTime ? $expected : new \DateTime($expected);
|
||||||
|
|
||||||
|
$this->assertLessThanOrEqual($precision, abs($expected->format('U') - $tested->format('U')));
|
||||||
|
}
|
||||||
|
|
||||||
protected function createSearchEngineMock()
|
protected function createSearchEngineMock()
|
||||||
{
|
{
|
||||||
$mock = $this->getMock('Alchemy\Phrasea\SearchEngine\SearchEngineInterface');
|
$mock = $this->getMock('Alchemy\Phrasea\SearchEngine\SearchEngineInterface');
|
||||||
|
@@ -1,107 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|
||||||
|
|
||||||
class randomTest extends \PhraseanetTestCase
|
|
||||||
{
|
|
||||||
protected $random;
|
|
||||||
|
|
||||||
public function setUp()
|
|
||||||
{
|
|
||||||
parent::setUp();
|
|
||||||
$this->random = new \random(self::$DI['app']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCleanTokens()
|
|
||||||
{
|
|
||||||
$expires_on = new DateTime('-5 minutes');
|
|
||||||
$usr_id = self::$DI['user']->getId();
|
|
||||||
$token = $this->random->getUrlToken(\random::TYPE_PASSWORD, $usr_id, $expires_on, 'some nice datas');
|
|
||||||
$this->random->cleanTokens(self::$DI['app']);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->random->helloToken($token);
|
|
||||||
$this->fail();
|
|
||||||
} catch (NotFoundHttpException $e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetUrlToken()
|
|
||||||
{
|
|
||||||
$usr_id = self::$DI['user']->getId();
|
|
||||||
$token = $this->random->getUrlToken(\random::TYPE_PASSWORD, $usr_id, null, 'some nice datas');
|
|
||||||
$datas = $this->random->helloToken($token);
|
|
||||||
$this->assertEquals('some nice datas', $datas['datas']);
|
|
||||||
$this->random->updateToken($token, 'some very nice datas');
|
|
||||||
$datas = $this->random->helloToken($token);
|
|
||||||
$this->assertEquals('some very nice datas', $datas['datas']);
|
|
||||||
$this->random->removeToken($token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testRemoveToken()
|
|
||||||
{
|
|
||||||
$this->testGetUrlToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testUpdateToken()
|
|
||||||
{
|
|
||||||
$this->testGetUrlToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testHelloToken()
|
|
||||||
{
|
|
||||||
$usr_id = self::$DI['user']->getId();
|
|
||||||
$token = $this->random->getUrlToken(\random::TYPE_PASSWORD, $usr_id, null, 'some nice datas');
|
|
||||||
$datas = $this->random->helloToken($token);
|
|
||||||
$this->assertEquals('some nice datas', $datas['datas']);
|
|
||||||
$this->assertNull($datas['expire_on']);
|
|
||||||
$created_on = new DateTime($datas['created_on']);
|
|
||||||
$date = new DateTime('-3 seconds');
|
|
||||||
$this->assertTrue($date < $created_on, "asserting that " . $date->format(DATE_ATOM) . " is before " . $created_on->format(DATE_ATOM));
|
|
||||||
$date = new DateTime();
|
|
||||||
$this->assertTrue($date >= $created_on);
|
|
||||||
$this->assertEquals('password', $datas['type']);
|
|
||||||
|
|
||||||
$this->random->removeToken($token);
|
|
||||||
try {
|
|
||||||
$this->random->helloToken($token);
|
|
||||||
$this->fail();
|
|
||||||
} catch (NotFoundHttpException $e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$expires_on = new DateTime('+5 minutes');
|
|
||||||
$usr_id = self::$DI['user']->getId();
|
|
||||||
$token = $this->random->getUrlToken(\random::TYPE_PASSWORD, $usr_id, $expires_on, 'some nice datas');
|
|
||||||
$datas = $this->random->helloToken($token);
|
|
||||||
$this->assertEquals('some nice datas', $datas['datas']);
|
|
||||||
$sql_expires = new DateTime($datas['expire_on']);
|
|
||||||
$this->assertTrue($sql_expires == $expires_on);
|
|
||||||
$created_on = new DateTime($datas['created_on']);
|
|
||||||
$date = new DateTime('-3 seconds');
|
|
||||||
$this->assertTrue($date < $created_on);
|
|
||||||
$date = new DateTime();
|
|
||||||
$this->assertTrue($date >= $created_on);
|
|
||||||
$this->assertEquals('password', $datas['type']);
|
|
||||||
|
|
||||||
$this->random->removeToken($token);
|
|
||||||
try {
|
|
||||||
$this->random->helloToken($token);
|
|
||||||
$this->fail();
|
|
||||||
} catch (NotFoundHttpException $e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$expires_on = new DateTime('-5 minutes');
|
|
||||||
$usr_id = self::$DI['user']->getId();
|
|
||||||
$token = $this->random->getUrlToken(\random::TYPE_PASSWORD, $usr_id, $expires_on, 'some nice datas');
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->random->helloToken($token);
|
|
||||||
$this->fail();
|
|
||||||
} catch (NotFoundHttpException $e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user