diff --git a/.env b/.env
index e13dd09..ce22709 100644
--- a/.env
+++ b/.env
@@ -41,3 +41,11 @@ LOCK_DSN=flock
SENTRY_DSN=
###< sentry/sentry-symfony ###
REDIS_DSN=redis://redis:6379
+
+### Altcha
+ALTCHA_HOST='http://localhost:3333'
+ALTCHA_BASE_URL=''
+ALTCHA_DEBUG=false
+ALTCHA_WORKERS=8
+ALTCHA_DELAY=100
+ALTCHA_MOCK_ERROR=false
diff --git a/config/services.yaml b/config/services.yaml
index 30bc817..404edfe 100644
--- a/config/services.yaml
+++ b/config/services.yaml
@@ -75,3 +75,19 @@ services:
$securityPattern: '%security_pattern%'
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
+
+ App\Altcha\Form\AltchaType:
+ arguments:
+ $altchaHost: "%env(string:ALTCHA_HOST)%"
+ $altchaBaseUrl: "%env(string:ALTCHA_BASE_URL)%"
+ $altchaDebug: "%env(bool:ALTCHA_DEBUG)%"
+ $altchaWorkers: "%env(string:ALTCHA_WORKERS)%"
+ $altchaDelay: "%env(string:ALTCHA_DELAY)%"
+ $altchaMockError: "%env(bool:ALTCHA_MOCK_ERROR)%"
+ tags:
+ - { name: form.type, alias: altcha}
+
+ App\Altcha\AltchaValidator:
+ arguments:
+ $altchaHost: "%env(string:ALTCHA_HOST)%"
+ $altchaBaseUrl: "%env(string:ALTCHA_BASE_URL)%"
\ No newline at end of file
diff --git a/src/Altcha/AltchaTransformer.php b/src/Altcha/AltchaTransformer.php
new file mode 100644
index 0000000..8378a7c
--- /dev/null
+++ b/src/Altcha/AltchaTransformer.php
@@ -0,0 +1,48 @@
+ $value) {
+ $model->{$property} = $value;
+ }
+
+ return $model;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function transform($value): string
+ {
+ if (empty($value)) {
+ return '';
+ }
+
+ $json = json_encode($value);
+
+ if (false === $json) {
+ return '';
+ }
+
+ return base64_encode($json);
+ }
+}
diff --git a/src/Altcha/AltchaValidator.php b/src/Altcha/AltchaValidator.php
new file mode 100644
index 0000000..793d969
--- /dev/null
+++ b/src/Altcha/AltchaValidator.php
@@ -0,0 +1,52 @@
+getForm();
+ $data = $form->getData();
+
+ $response = $this->httpClient->request(
+ 'POST',
+ $this->altchaHost.$this->altchaBaseUrl.'/verify',
+ [
+ 'body' => json_encode($data),
+ 'headers' => [
+ 'Content-Type' => 'application/json',
+ ],
+ ],
+ );
+
+ if (Response::HTTP_OK !== $response->getStatusCode()) {
+ $form->addError(new FormError($this->translator->trans('altcha.validator.server_validation_error', [], 'form')));
+
+ return;
+ }
+
+ $content = $response->getContent();
+ $parsedResponse = json_decode($content);
+
+ if (true !== $parsedResponse->success) {
+ $form->addError(new FormError($this->translator->trans('altcha.validator.server_validation_error', [], 'form')));
+
+ return;
+ }
+ }
+}
diff --git a/src/Altcha/Form/AltchaModel.php b/src/Altcha/Form/AltchaModel.php
new file mode 100644
index 0000000..abb2ba5
--- /dev/null
+++ b/src/Altcha/Form/AltchaModel.php
@@ -0,0 +1,39 @@
+addModelTransformer(new AltchaTransformer());
+
+ $builder->addEventListener(FormEvents::POST_SUBMIT, [$this->altchaValidator, 'validate']);
+ }
+
+ public function buildView(FormView $view, FormInterface $form, array $options)
+ {
+ $translations = [
+ 'label' => $this->translator->trans('altcha.widget.label', [], 'form'),
+ 'verified' => $this->translator->trans('altcha.widget.verified', [], 'form'),
+ 'verifying' => $this->translator->trans('altcha.widget.verifying', [], 'form'),
+ 'waitAlert' => $this->translator->trans('altcha.widget.waitalert', [], 'form'),
+ 'error' => $this->translator->trans('altcha.widget.error', [], 'form'),
+ 'expired' => $this->translator->trans('altcha.widget.expired', [], 'form'),
+ ];
+ $view->vars['translations'] = json_encode($translations);
+ $view->vars['challengeJson'] = $this->requestChallenge();
+ $view->vars['debug'] = $this->altchaDebug;
+ $view->vars['workers'] = $this->altchaWorkers;
+ $view->vars['delay'] = $this->altchaDelay;
+ $view->vars['mockError'] = $this->altchaMockError;
+ }
+
+ private function requestChallenge(): string
+ {
+ $resp = $this->httpClient->request('GET', $this->altchaHost.$this->altchaBaseUrl.'/request');
+ if (Response::HTTP_OK === $resp->getStatusCode()) {
+ return $resp->getContent();
+ }
+
+ return '';
+ }
+
+ public function getParent(): string
+ {
+ return TextType::class;
+ }
+
+ public function getName(): string
+ {
+ return $this->getBlockPrefix();
+ }
+
+ public function getBlockPrefix(): string
+ {
+ return 'altcha';
+ }
+}
diff --git a/src/Form/LoginType.php b/src/Form/LoginType.php
index c857984..a3e4193 100644
--- a/src/Form/LoginType.php
+++ b/src/Form/LoginType.php
@@ -2,12 +2,13 @@
namespace App\Form;
+use App\Altcha\Form\AltchaType;
use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
-use Symfony\Component\Form\Extension\Core\Type\PasswordType;
-use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
+use Symfony\Component\Form\Extension\Core\Type\TextType;
+use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
+use Symfony\Component\Form\Extension\Core\Type\PasswordType;
class LoginType extends AbstractType
{
@@ -27,6 +28,10 @@ class LoginType extends AbstractType
'translation_domain' => 'form',
'label' => 'form.label.remember_me',
])
+ ->add('altcha', AltchaType::class, [
+ 'label' => false,
+ 'required' => true,
+ ])
;
}
diff --git a/src/Hydra/Client.php b/src/Hydra/Client.php
index 00592f9..f0e7569 100644
--- a/src/Hydra/Client.php
+++ b/src/Hydra/Client.php
@@ -9,19 +9,17 @@ use Symfony\Contracts\HttpClient\ResponseInterface;
class Client
{
- private HttpClientInterface $client;
private const MAX_RETRY = 3;
private const SLEEP_TIME = [
5,
500,
5000,
];
- private string $hydraAdminBaseUrl;
- public function __construct(HttpClientInterface $client, string $hydraAdminBaseUrl)
- {
- $this->client = $client;
- $this->hydraAdminBaseUrl = $hydraAdminBaseUrl;
+ public function __construct(
+ private readonly HttpClientInterface $client,
+ private readonly string $hydraAdminBaseUrl
+ ) {
}
public function fetchLoginRequestInfo(string $loginChallenge): ResponseInterface
diff --git a/templates/altcha.html.twig b/templates/altcha.html.twig
new file mode 100644
index 0000000..e70036f
--- /dev/null
+++ b/templates/altcha.html.twig
@@ -0,0 +1,18 @@
+{% block altcha_widget %}
+
+
+{% endblock %}
\ No newline at end of file