Compare commits
4 commits
Author | SHA1 | Date | |
---|---|---|---|
e59bed36db | |||
b11cea13b3 | |||
Simon Vieille | 33ac16fac2 | ||
Simon Vieille | 64d4a326ec |
|
@ -9,7 +9,7 @@ services:
|
|||
environment:
|
||||
- MARIADB_ROOT_PASSWORD=root
|
||||
|
||||
steps:
|
||||
pipeline:
|
||||
db_wait:
|
||||
image: gitnet.fr/deblan/timeout:latest
|
||||
commands:
|
||||
|
@ -21,7 +21,7 @@ steps:
|
|||
- mysql -hdb -uroot -proot -e "CREATE DATABASE app"
|
||||
|
||||
config:
|
||||
image: deblan/php:${PHP_VERSION}
|
||||
image: deblan/php:8.1
|
||||
commands:
|
||||
- echo APP_ENV=prod >> .env.local
|
||||
- echo APP_SECRET=$(openssl rand -hex 32) >> .env.local
|
||||
|
|
33
CHANGELOG.md
33
CHANGELOG.md
|
@ -1,35 +1,6 @@
|
|||
## [Unreleased]
|
||||
|
||||
## [v1.23.0] - 2023-09-28
|
||||
### Changed
|
||||
* upgrade murph/murph-core
|
||||
|
||||
## [v1.22.0] - 2023-09-28
|
||||
### Added
|
||||
* update woodpecker ci base file
|
||||
### Fixed
|
||||
* fix #1: add UniqueEntity constraint in the User entity
|
||||
### Changed
|
||||
* upgrade murph/murph-core
|
||||
|
||||
## [1.21.0] - 2023-08-11
|
||||
### Changed
|
||||
* upgrade murph/murph-core
|
||||
|
||||
## [1.20.0] - 2023-07-27
|
||||
### Fixed
|
||||
* fix collection widget: allow_add/allow_delete and prototype
|
||||
### Added
|
||||
* add user admin controller and simples views in default files
|
||||
* add chdir in the console entrypoint
|
||||
### Changed
|
||||
* upgrade murph/murph-core
|
||||
|
||||
## [1.19.0] - 2023-04-15
|
||||
### Changed
|
||||
* upgrade murph/murph-core
|
||||
|
||||
## [1.18.0] - 2023-01-13
|
||||
## [1.18.0] 2023-01-13
|
||||
### Added
|
||||
* feat(dep): update dependencies
|
||||
* feat(update): apply new recipe for phpunit
|
||||
|
@ -57,7 +28,7 @@
|
|||
* fix(config): fix firewall config
|
||||
|
||||
|
||||
## [1.17.0] - 2022-11-19
|
||||
## [1.17.0] 2022-11-19
|
||||
### Changed
|
||||
* upgrade murph/murph-core
|
||||
* replace annotation with attributes
|
||||
|
|
|
@ -10,8 +10,6 @@ if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) {
|
|||
|
||||
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
|
||||
|
||||
chdir(__DIR__.'/../');
|
||||
|
||||
return function (array $context) {
|
||||
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
|
||||
|
||||
|
|
|
@ -7,17 +7,17 @@
|
|||
"prefer-stable": true,
|
||||
"require": {
|
||||
"php": ">=8.0.0",
|
||||
"murph/murph-core": "^1.23"
|
||||
"murph/murph-core": "v2.x-dev"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/browser-kit": "^5.4",
|
||||
"symfony/css-selector": "^5.4",
|
||||
"symfony/debug-bundle": "^5.4",
|
||||
"symfony/browser-kit": "^6.0.0",
|
||||
"symfony/css-selector": "^6.0.0",
|
||||
"symfony/debug-bundle": "^6.0.0",
|
||||
"symfony/maker-bundle": "^1.0",
|
||||
"symfony/phpunit-bridge": "^6.2",
|
||||
"symfony/stopwatch": "^5.4",
|
||||
"symfony/var-dumper": "^5.4",
|
||||
"symfony/web-profiler-bundle": "^5.4"
|
||||
"symfony/phpunit-bridge": "^6.2.0",
|
||||
"symfony/stopwatch": "^6.2.0",
|
||||
"symfony/var-dumper": "^6.2.0",
|
||||
"symfony/web-profiler-bundle": "^6.2.0"
|
||||
},
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
|
@ -63,7 +63,7 @@
|
|||
"extra": {
|
||||
"symfony": {
|
||||
"allow-contrib": false,
|
||||
"require": "5.4.*"
|
||||
"require": "6.2.*"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ core:
|
|||
# - image/png
|
||||
# - image/jpg
|
||||
# - image/jpeg
|
||||
# - image/webp
|
||||
# - image/gif
|
||||
# - image/svg+xml
|
||||
# - video/mp4
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
# See the configuration reference at https://github.com/scheb/2fa/blob/master/doc/configuration.md
|
||||
scheb_two_factor:
|
||||
google:
|
||||
totp:
|
||||
enabled: true
|
||||
issuer: "Murph"
|
||||
server_name:
|
||||
digits: 6
|
||||
window: 1
|
||||
template: "@Core/auth/2fa.html.twig"
|
||||
security_tokens:
|
||||
|
|
|
@ -1,12 +1,4 @@
|
|||
security:
|
||||
encoders:
|
||||
App\Entity\User:
|
||||
algorithm: auto
|
||||
|
||||
access_decision_manager:
|
||||
strategy: consensus
|
||||
allow_if_all_abstain: false
|
||||
|
||||
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
|
||||
enable_authenticator_manager: true
|
||||
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
|
||||
|
@ -32,8 +24,7 @@ security:
|
|||
two_factor:
|
||||
auth_form_path: 2fa_login # The route name you have used in the routes.yaml
|
||||
check_path: 2fa_login_check # The route name you have used in the routes.yaml
|
||||
guard:
|
||||
authenticators:
|
||||
custom_authenticators:
|
||||
- App\Core\Authenticator\LoginFormAuthenticator
|
||||
form_login:
|
||||
login_path: auth_login
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Core\Controller\User\UserAdminController as BaseUserAdminController;
|
||||
use App\Core\Crud\CrudConfiguration;
|
||||
use App\Core\Factory\UserFactory as Factory;
|
||||
use App\Core\Manager\EntityManager;
|
||||
use App\Core\Security\TokenGenerator;
|
||||
use App\Entity\User as Entity;
|
||||
use App\Repository\UserRepositoryQuery as RepositoryQuery;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
class UserAdminController extends BaseUserAdminController
|
||||
{
|
||||
#[Route(path: '/admin/user/{page}', name: 'admin_user_index', methods: ['GET'], requirements: ['page' => '\d+'])]
|
||||
public function index(RepositoryQuery $query, Request $request, Session $session, int $page = 1): Response
|
||||
{
|
||||
return parent::index($query, $request, $session, $page);
|
||||
}
|
||||
|
||||
#[Route(path: '/admin/user/new', name: 'admin_user_new', methods: ['GET', 'POST'])]
|
||||
public function new(Factory $factory, EntityManager $entityManager, Request $request, TokenGenerator $tokenGenerator): Response
|
||||
{
|
||||
return parent::new($factory, $entityManager, $request, $tokenGenerator);
|
||||
}
|
||||
|
||||
#[Route(path: '/admin/user/show/{entity}', name: 'admin_user_show', methods: ['GET'])]
|
||||
public function show(Entity $entity): Response
|
||||
{
|
||||
return parent::show($entity);
|
||||
}
|
||||
|
||||
#[Route(path: '/admin/user/filter', name: 'admin_user_filter', methods: ['GET'])]
|
||||
public function filter(Session $session): Response
|
||||
{
|
||||
return parent::filter($session);
|
||||
}
|
||||
|
||||
#[Route(path: '/admin/user/edit/{entity}', name: 'admin_user_edit', methods: ['GET', 'POST'])]
|
||||
public function edit(Entity $entity, EntityManager $entityManager, Request $request): Response
|
||||
{
|
||||
return parent::edit($entity, $entityManager, $request);
|
||||
}
|
||||
|
||||
#[Route(path: '/admin/user/inline_edit/{entity}/{context}/{label}', name: 'admin_user_inline_edit', methods: ['GET', 'POST'])]
|
||||
public function inlineEdit(string $context, string $label, Entity $entity, EntityManager $entityManager, Request $request): Response
|
||||
{
|
||||
return parent::inlineEdit($context, $label, $entity, $entityManager, $request);
|
||||
}
|
||||
|
||||
#[Route(path: '/admin/user/delete/{entity}', name: 'admin_user_delete', methods: ['DELETE', 'POST'])]
|
||||
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
|
||||
{
|
||||
return parent::delete($entity, $entityManager, $request);
|
||||
}
|
||||
|
||||
#[Route(path: '/admin/user/resetting_request/{entity}', name: 'admin_user_resetting_request', methods: ['POST'])]
|
||||
public function requestResetting(Entity $entity, EventDispatcherInterface $eventDispatcher, Request $request): Response
|
||||
{
|
||||
return parent::requestResetting($entity, $eventDispatcher, $request);
|
||||
}
|
||||
|
||||
protected function getConfiguration(): CrudConfiguration
|
||||
{
|
||||
if ($this->configuration) {
|
||||
return $this->configuration;
|
||||
}
|
||||
|
||||
return parent::getConfiguration()
|
||||
->setView('form', 'admin/user_admin/_form.html.twig')
|
||||
->setView('show_entity', 'admin/user_admin/_show.html.twig')
|
||||
;
|
||||
}
|
||||
}
|
|
@ -6,14 +6,14 @@ use App\Core\Doctrine\Timestampable;
|
|||
use App\Core\Entity\EntityInterface;
|
||||
use App\Repository\UserRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Scheb\TwoFactorBundle\Model\Google\TwoFactorInterface;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Scheb\TwoFactorBundle\Model\Totp\TwoFactorInterface;
|
||||
use Scheb\TwoFactorBundle\Model\Totp\TotpConfiguration;
|
||||
use Scheb\TwoFactorBundle\Model\Totp\TotpConfigurationInterface;
|
||||
|
||||
#[ORM\Entity(repositoryClass: UserRepository::class)]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
#[UniqueEntity('email')]
|
||||
class User implements PasswordAuthenticatedUserInterface, UserInterface, TwoFactorInterface, EntityInterface
|
||||
{
|
||||
use Timestampable;
|
||||
|
@ -162,24 +162,30 @@ class User implements PasswordAuthenticatedUserInterface, UserInterface, TwoFact
|
|||
return null !== $this->getTotpSecret();
|
||||
}
|
||||
|
||||
public function isGoogleAuthenticatorEnabled(): bool
|
||||
{
|
||||
return $this->isTotpAuthenticationEnabled();
|
||||
}
|
||||
|
||||
public function getGoogleAuthenticatorUsername(): string
|
||||
public function getTotpAuthenticationUsername(): string
|
||||
{
|
||||
return $this->getEmail();
|
||||
}
|
||||
|
||||
public function getGoogleAuthenticatorSecret(): ?string
|
||||
public function getTotpAuthenticationSecret(): ?string
|
||||
{
|
||||
return $this->getTotpSecret();
|
||||
}
|
||||
|
||||
public function setGoogleAuthenticatorSecret(?string $googleAuthenticatorSecret): void
|
||||
public function setTotpAuthenticationSecret(?string $totpAuthenticatorSecret): void
|
||||
{
|
||||
$this->setTotpSecret($googleAuthenticatorSecret);
|
||||
$this->setTotpSecret($totpAuthenticatorSecret);
|
||||
}
|
||||
|
||||
public function getTotpAuthenticationConfiguration(): ?TotpConfigurationInterface
|
||||
{
|
||||
// You could persist the other configuration options in the user entity to make it individual per user.
|
||||
return new TotpConfiguration(
|
||||
$this->getTotpAuthenticationSecret(),
|
||||
TotpConfiguration::ALGORITHM_SHA1,
|
||||
20,
|
||||
6
|
||||
);
|
||||
}
|
||||
|
||||
public function getPasswordRequestedAt(): ?\DateTimeInterface
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Security\Voter;
|
||||
|
||||
use App\Core\Entity\EntityInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
class EntityVoter extends Voter
|
||||
{
|
||||
public const EDIT = 'edit';
|
||||
public const VIEW = 'show';
|
||||
public const DELETE = 'delete';
|
||||
|
||||
protected function supports(string $attribute, mixed $subject): bool
|
||||
{
|
||||
// replace with your own logic
|
||||
// https://symfony.com/doc/current/security/voters.html
|
||||
return in_array($attribute, [self::EDIT, self::VIEW, self::DELETE])
|
||||
&& $subject instanceof EntityInterface;
|
||||
}
|
||||
|
||||
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
|
||||
{
|
||||
$user = $token->getUser();
|
||||
|
||||
if (!$user instanceof UserInterface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ($attribute) {
|
||||
case self::EDIT:
|
||||
return true;
|
||||
|
||||
break;
|
||||
|
||||
case self::VIEW:
|
||||
return true;
|
||||
|
||||
break;
|
||||
|
||||
case self::DELETE:
|
||||
return true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
{{ include('@Core/user/user_admin/_form.html.twig') }}
|
|
@ -1 +0,0 @@
|
|||
{{ include('@Core/user/user_admin/_show.html.twig') }}
|
Loading…
Reference in a new issue