Init Gitea

This commit is contained in:
dqj
2025-10-06 21:45:33 +09:00
commit c8607205a2
33 changed files with 4268 additions and 0 deletions

View File

@@ -0,0 +1,410 @@
<?php
/*
* This file is part of EC-CUBE
*
* Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
*
* http://www.ec-cube.co.jp/
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Plugin\Passkeys\EventListener;
use Eccube\Common\EccubeConfig;
use Eccube\Entity\BaseInfo;
use Eccube\Entity\Customer;
use Eccube\Entity\Master\CustomerStatus;
use Eccube\Repository\BaseInfoRepository;
use Eccube\Request\Context;
use Plugin\Passkeys\Repository\PasskeysAuthTypeRepository;
use Plugin\Passkeys\Repository\PasskeysAuthCustomerCookieRepository;
use Plugin\Passkeys\Service\CustomerPasskeysAuthService;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Http\Event\LoginSuccessEvent;
use Symfony\Component\Security\Http\Event\LogoutEvent;
use Symfony\Contracts\EventDispatcher\Event;
class CustomerPasskeysAuthListener implements EventSubscriberInterface
{
/**
* @var EccubeConfig
*/
protected $eccubeConfig;
/**
* @var Context
*/
protected $requestContext;
/**
* @var UrlGeneratorInterface
*/
protected $router;
/**
* @var CustomerPasskeysAuthService
*/
protected $customerPasskeysAuthService;
/**
* @var PasskeysAuthTypeRepository
*/
protected PasskeysAuthTypeRepository $PasskeysAuthTypeRepository;
/**
* @var PasskeysAuthCustomerCookieRepository
*/
protected PasskeysAuthCustomerCookieRepository $PasskeysAuthCustomerCookieRepository;
/**
* @var BaseInfo|object|null
*/
protected $baseInfo;
/**
* @var Session
*/
protected $session;
/**
* 通常(ログイン・マイページ)ルート.
*/
protected $default_routes;
/**
* 重要操作ルート.
*/
protected $include_routes;
/**
* @param Context $requestContext
* @param UrlGeneratorInterface $router
* @param CustomerPasskeysAuthService $customerPasskeysAuthService
* @param PasskeysAuthTypeRepository $PasskeysAuthTypeRepository
* @param PasskeysAuthCustomerCookieRepository $PasskeysAuthCustomerCookieRepository
* @param BaseInfoRepository $baseInfoRepository
* @param SessionInterface $session
*/
public function __construct(
Context $requestContext,
UrlGeneratorInterface $router,
CustomerPasskeysAuthService $customerPasskeysAuthService,
PasskeysAuthTypeRepository $PasskeysAuthTypeRepository,
PasskeysAuthCustomerCookieRepository $PasskeysAuthCustomerCookieRepository,
BaseInfoRepository $baseInfoRepository,
SessionInterface $session
) {
$this->requestContext = $requestContext;
$this->router = $router;
$this->customerPasskeysAuthService = $customerPasskeysAuthService;
$this->baseInfo = $baseInfoRepository->find(1);
$this->PasskeysAuthTypeRepository = $PasskeysAuthTypeRepository;
$this->PasskeysAuthCustomerCookieRepository = $PasskeysAuthCustomerCookieRepository;
$this->session = $session;
$this->default_routes = $this->customerPasskeysAuthService->getDefaultAuthRoutes();
$this->include_routes = $this->customerPasskeysAuthService->getIncludeRoutes();
}
/**
* @return array
*/
public static function getSubscribedEvents(): array
{
return [
KernelEvents::CONTROLLER_ARGUMENTS => ['onKernelController', 7],
KernelEvents::REQUEST => 'onKernelRequest',
LoginSuccessEvent::class => ['onLoginSuccess'],
LogoutEvent::class => 'logoutEvent',
];
}
public function onKernelRequest(RequestEvent $event)
{
log_info('pk:onKernelRequest');
if (!$event->isMainRequest()) {
log_info('pk:onKernelRequest-NotMainRequest');
return;
}
if ($this->requestContext->isAdmin()) {
log_info('pk:onKernelRequest-isAdmin');
return;
}
if (!$this->baseInfo->isPasskeysUse()) {
log_info('pk:onKernelRequest-NoPK');
return;
}
$route = $event->getRequest()->attributes->get('_route');
if($route !== 'mypage_login' && $route !== 'plg_customer_passkey_page'){
$this->setCallbackRoute($route);
log_info('pk:onKernelRequest set:'.$route);
}
}
/**
* リクエスト受信時イベントハンドラ.
*
* @param ControllerArgumentsEvent $event
*/
public function onKernelController(ControllerArgumentsEvent $event)
{
//log_info('pk:onKernelController');
if (!$event->isMainRequest()) {
// サブリクエストの場合、処理なし
log_info('pk:onKernelController-NotMainRequest');
return;
}
if ($this->requestContext->isAdmin()) {
// バックエンドURLの場合、処理なし
log_info('pk:onKernelController-isAdmin');
return;
}
if (!$this->baseInfo->isPasskeysUse()) {
log_info('pk:onKernelControllerNoPK');
return;
}
$route = $event->getRequest()->attributes->get('_route');
$uri = $event->getRequest()->getRequestUri();
if (!$this->isDefaultRoute($route, $uri) && !$this->isIncludeRoute($route, $uri)) {
// 重要操作指定ではなく、マイページ系列ではない場合、処理なし
return;
}
$Customer = $this->requestContext->getCurrentUser();
log_info('pk:onKernelController2:'.$Customer);
//TODO: may try passkeys before form login in the future.
//$this->passkeyProcess($event, $Customer, $route);
if ($Customer instanceof Customer) {
if(!$Customer->isEnablePasskeys()){
log_info('pk:onKernelController:passkey disabled by user');
return;
}else{//for debug
log_info('pk:onKernelController:passkey enabled by user');
}
if ($Customer->getStatus()->getId() !== CustomerStatus::REGULAR) {
// ログインしていない場合、処理なし
return;
}
if (!$this->isDefaultRoute($route, $uri) && !$this->isIncludeRoute($route, $uri)) {
// 重要操作指定ではなく、マイページ系列ではない場合、処理なし
return;
}
$this->passkeyProcess($event, $Customer, $route);
}else{
log_info('pk:onKernelController:no customer obj yet');
//TODO: Jump to original URL before login page.
//$referer = $event->getRequest()->headers->get('referer');
//$this->setCallbackRoute($uri);
}
}
/**
* ログイン完了 イベントハンドラ.
*
* @param LoginSuccessEvent $event
*
* @return RedirectResponse|void
*/
public function onLoginSuccess(LoginSuccessEvent $event)
{
//log_info('pk:onLoginSuccess1');
if ($this->requestContext->isAdmin()) {
// バックエンドURLの場合処理なし
return;
}
//log_info('pk:onLoginSuccess2');
if (!$this->baseInfo->isPasskeysUse()) {
// Return if non Passkeys
return;
}
//log_info('pk:onLoginSuccess3');
if ($this->requestContext->getCurrentUser() === null) {
// ログインしていない場合は処理なし
return;
}
log_info('pk:onLoginSuccess5');
$Customer = $this->requestContext->getCurrentUser();
if(!$Customer->isEnablePasskeys()){
log_info('pk:onKernelController:passkey disabled by user');
return;
}else{//for debug
log_info('pk:onKernelController:passkey enabled by user');
}
$this->passkeyProcess(
$event,
$Customer,
$event->getRequest()->attributes->get('_route'));
}
/**
* ログアウトする前に全ての2FA認証クッキーを消す
*
* @param LogoutEvent $logoutEvent ログアウトイベント
*
* @return void
*/
public function logoutEvent(LogoutEvent $logoutEvent)
{
$this->customerPasskeysAuthService->clearPKAuthCookies($logoutEvent->getRequest(), $logoutEvent->getResponse());
$Customer = $this->requestContext->getCurrentUser();
if ($Customer !== null) {
$this->PasskeysAuthCustomerCookieRepository->deleteByCustomer($Customer);
}
$this->session->remove(CustomerPasskeysAuthService::SESSION_CALL_BACK_URL);
}
/**
* ルート・URIが個別認証対象かチェック.
*
* @param string $route
* @param string $uri
*
* @return bool
*/
private function isDefaultRoute(string $route, string $uri): bool
{
return $this->isTargetRoute($this->default_routes, $route, $uri);
}
/**
* ルート・URIが対象であるかチェック.
*
* @param array $targetRoutes
* @param string $route
* @param string $uri
*
* @return bool
*/
private function isTargetRoute(array $targetRoutes, string $route, string $uri): bool
{
// ルートで認証
if (in_array($route, $targetRoutes)) {
return true;
}
// URIで認証
foreach ($targetRoutes as $r) {
if ($r != '' && $r !== '/' && strpos($uri, $r) === 0) {
return true;
}
}
return false;
}
/**
* ルート・URIが個別認証対象かチェック.
*
* @param string $route
* @param string $uri
*
* @return bool
*/
private function isIncludeRoute(string $route, string $uri): bool
{
return $this->isTargetRoute($this->include_routes, $route, $uri);
}
/**
* Passkey authentication
*
* @param Event $event
* @param Customer $Customer
* @param string $route
*
* @return mixed
*/
private function passkeyProcess($event, $Customer, $route)
{
log_info('pk:passkeyProcess1');
if (!$this->baseInfo->isPasskeysUse()) {
return;
}
//log_info('pk:passkeyProcess2');
$is_auth = $this->customerPasskeysAuthService->isAuthed($Customer, $route);
if ($is_auth) {
$my_route = $this->session->get(CustomerPasskeysAuthService::SESSION_CALL_BACK_URL);
log_info('pk:passkey auth done:'.$route.'|'.$my_route);
if($my_route !== null && $my_route !== $route){
//$this->session->remove(CustomerPasskeysAuthService::SESSION_CALL_BACK_URL);
$my_url = $this->router->generate($my_route, [], UrlGeneratorInterface::ABSOLUTE_PATH);
if ($event instanceof ControllerArgumentsEvent) {
log_info('pk:passkey auth done1:'.$my_url.'|||');
$event->setController(function () use ($my_url) {
return new RedirectResponse($my_url, $status = 302);
});
} else {
log_info('pk:passkey auth done2:'.$my_url.'|||');
$event->setResponse(new RedirectResponse($my_url, $status = 302));
}
}
else{
log_info('pk:passkey auth done3: remove SESSION_CALL_BACK_URL');
$this->session->remove(CustomerPasskeysAuthService::SESSION_CALL_BACK_URL);
}
return;
}
//$this->setCallbackRoute($route);
log_info('pk:passkeyProcess3');
$url = $this->router->generate('plg_customer_passkey_page', [], UrlGeneratorInterface::ABSOLUTE_PATH);
//TODO: may try passkeys before form ligin in the future.
/*if($Customer !== null && $Customer->getStatus()->getId() === CustomerStatus::REGULAR){
$url.= '?pkreg=1';
}*/
log_info('pk:plg_customer_passkey_page_process:'.$url.'|||');
if ($event instanceof ControllerArgumentsEvent) {
log_info('pk:setController:'.$url.'|||');
$event->setController(function () use ($url) {
return new RedirectResponse($url, $status = 302);
});
} else {
log_info('pk:setResponse:'.$url.'|||');
$event->setResponse(new RedirectResponse($url, $status = 302));
}
}
/**
* コールバックルートをセッションへ設定.
*
* @param string|null $route
*/
private function setCallbackRoute(?string $route)
{
log_info('pk:setCallbackRoute:'.$route);
if ($route) {
log_info('pk:setCallbackRoute1:'.($this->session !=null ).'|'.CustomerPasskeysAuthService::SESSION_CALL_BACK_URL);
$this->session->set(CustomerPasskeysAuthService::SESSION_CALL_BACK_URL, $route);
}
}
}