Initial commit

This commit is contained in:
2019-05-26 15:57:49 +02:00
commit 9f74ec1089
34290 changed files with 5059123 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace BetterPassword;
use Thelia\Module\BaseModule;
class BetterPassword extends BaseModule
{
/** @var string */
const DOMAIN_NAME = 'betterpassword';
const VAR_REGULAR_EXPRESSION = "password_expression";
const VAR_PASSWORD_REQUIREMENTS = "password_requirements";
}

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" ?>
<config xmlns="http://thelia.net/schema/dic/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd">
<forms>
<form name="betterpassword.configuration" class="BetterPassword\Form\ConfigForm" />
</forms>
<services>
<service id="betterpassword.listener" class="BetterPassword\EventListeners\FormHandler">
<argument type="service" id="request_stack"/>
<tag name="kernel.event_subscriber"/>
</service>
</services>
<hooks>
<hook id="betterpassword.configuration.hook" class="BetterPassword\Hook\HookManager">
<tag name="hook.event_listener" event="module.configuration" type="back" method="onModuleConfigure" />
</hook>
</hooks>
</config>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="http://thelia.net/schema/dic/module"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://thelia.net/schema/dic/module http://thelia.net/schema/dic/module/module-2_2.xsd">
<fullnamespace>BetterPassword\BetterPassword</fullnamespace>
<descriptive locale="en_US">
<title>Require your customers to use secure password</title>
</descriptive>
<descriptive locale="fr_FR">
<title>Imposer des mots de passe sécurisés à vos clients</title>
</descriptive>
<languages>
<language>en_US</language>
<language>fr_FR</language>
</languages>
<version>1.0.0</version>
<authors>
<author>
<name>Franck Allimant</name>
<company>CQFDev</company>
<email>thelia@cqfdev.fr</email>
<website>www.cqfdev.fr</website>
</author>
</authors>
<type>classic</type>
<thelia>2.3.0</thelia>
<stability>other</stability>
<mandatory>0</mandatory>
<hidden>0</hidden>
</module>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
<route id="betterpassword.config" path="/admin/module/betterpassword/configure" methods="post">
<default key="_controller">BetterPassword\Controller\ConfigureController::configure</default>
</route>
</routes>

View File

@@ -0,0 +1,83 @@
<?php
/*************************************************************************************/
/* Copyright (c) Franck Allimant, CQFDev */
/* email : thelia@cqfdev.fr */
/* web : http://www.cqfdev.fr */
/* */
/* For the full copyright and license information, please view the LICENSE */
/* file that was distributed with this source code. */
/*************************************************************************************/
/**
* Created by Franck Allimant, CQFDev <franck@cqfdev.fr>
* Date: 03/03/2019 18:30
*/
namespace BetterPassword\Controller;
use BetterPassword\BetterPassword;
use Thelia\Controller\Admin\BaseAdminController;
use Thelia\Core\Security\AccessManager;
use Thelia\Core\Security\Resource\AdminResources;
use Thelia\Form\Exception\FormValidationException;
use Thelia\Tools\URL;
class ConfigureController extends BaseAdminController
{
public function configure()
{
if (null !== $response = $this->checkAuth(AdminResources::MODULE, 'betterpassword', AccessManager::UPDATE)) {
return $response;
}
$configurationForm = $this->createForm('betterpassword.configuration');
$message = null;
try {
$form = $this->validateForm($configurationForm);
// Get the form field values
$data = $form->getData();
foreach ($data as $name => $value) {
if (is_array($value)) {
foreach ($value as $locale => $text) {
BetterPassword::setConfigValue($name, $text, $locale);
}
} else {
BetterPassword::setConfigValue($name, $value);
}
}
// Log configuration modification
$this->adminLogAppend(
"betterpassword.configuration.message",
AccessManager::UPDATE,
"Better Password configuration updated"
);
// Redirect to the success URL,
if ($this->getRequest()->get('save_mode') == 'stay') {
// If we have to stay on the same page, redisplay the configuration page/
$url = '/admin/module/BetterPassword';
} else {
// If we have to close the page, go back to the module back-office page.
$url = '/admin/modules';
}
return $this->generateRedirect(URL::getInstance()->absoluteUrl($url));
} catch (FormValidationException $ex) {
$message = $this->createStandardFormValidationErrorMessage($ex);
} catch (\Exception $ex) {
$message = $ex->getMessage();
}
$this->setupFormErrorContext(
$this->getTranslator()->trans("BetterPassword configuration", [], BetterPassword::DOMAIN_NAME),
$message,
$configurationForm,
$ex
);
return $this->generateRedirect(URL::getInstance()->absoluteUrl('/admin/module/BetterPassword'));
}
}

View File

@@ -0,0 +1,104 @@
<?php
/*************************************************************************************/
/* Copyright (c) Franck Allimant, CQFDev */
/* email : thelia@cqfdev.fr */
/* web : http://www.cqfdev.fr */
/* */
/* For the full copyright and license information, please view the LICENSE */
/* file that was distributed with this source code. */
/*************************************************************************************/
/**
* Created by Franck Allimant, CQFDev <franck@cqfdev.fr>
* Date: 03/03/2019 17:38
*/
namespace BetterPassword\EventListeners;
use BetterPassword\BetterPassword;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\ExecutionContextInterface;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Event\TheliaFormEvent;
use Thelia\Core\HttpFoundation\Request;
use Thelia\Core\Translation\Translator;
class FormHandler implements EventSubscriberInterface
{
/** @var RequestStack */
protected $requestStack;
/**
* FormHandler constructor.
* @param RequestStack $requestStack
*/
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
}
public function changeCreatePasswordVerification(TheliaFormEvent $event)
{
$this->changePasswordVerification($event, 'password');
}
public function changeUpdatePasswordVerification(TheliaFormEvent $event)
{
$this->changePasswordVerification($event, 'password');
}
protected function getLocale()
{
/** @var Request $request */
$request = $this->requestStack->getCurrentRequest();
return $request->getSession()->getLang()->getLocale();
}
public function changePasswordVerification(TheliaFormEvent $event, $fieldName)
{
$formBuilder = $event->getForm()->getFormBuilder();
$passwordField = $formBuilder->get($fieldName);
$options = $passwordField->getOptions();
$type = $passwordField->getType()->getName();
$options['constraints'] = [
new NotBlank(),
new Callback([ "methods" => [[ $this, "checkPasswordValidity" ]]])
];
$options['label_attr']['help'] = BetterPassword::getConfigValue('password_requirements', '', $this->getLocale());
$formBuilder->add($fieldName, $type, $options);
}
public function checkPasswordValidity($value, ExecutionContextInterface $context)
{
$expression = BetterPassword::getConfigValue('password_expression', null);
if (null !== $expression && ! preg_match("/$expression/", $value)) {
$context->addViolation(
Translator::getInstance()->trans(
"Your password does not match the requirements : %requirement_text",
[
'%requirement_text' => BetterPassword::getConfigValue('password_requirements', '', $this->getLocale())
],
BetterPassword::DOMAIN_NAME
)
);
}
}
public static function getSubscribedEvents()
{
return [
TheliaEvents::FORM_AFTER_BUILD . ".thelia_customer_create" => ['changeCreatePasswordVerification', 128],
TheliaEvents::FORM_AFTER_BUILD . ".thelia_customer_password_update" => ['changeUpdatePasswordVerification', 128]
];
}
}

View File

@@ -0,0 +1,64 @@
<?php
/*************************************************************************************/
/* Copyright (c) Franck Allimant, CQFDev */
/* email : thelia@cqfdev.fr */
/* web : http://www.cqfdev.fr */
/* */
/* For the full copyright and license information, please view the LICENSE */
/* file that was distributed with this source code. */
/*************************************************************************************/
/**
* Created by Franck Allimant, CQFDev <franck@cqfdev.fr>
* Date: 03/03/2019 18:26
*/
namespace BetterPassword\Form;
use BetterPassword\BetterPassword;
use Symfony\Component\Validator\Constraints\NotBlank;
use Thelia\Core\Translation\Translator;
use Thelia\Form\BaseForm;
class ConfigForm extends BaseForm
{
protected function buildForm()
{
$translator = Translator::getInstance();
$this->formBuilder
->add(
BetterPassword::VAR_REGULAR_EXPRESSION,
'text',
[
'constraints' => [
new NotBlank(),
],
'label' => $translator->trans('Regular expression to match', [], BetterPassword::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans(
'This is the regular expression the passwords must match.',
[],
BetterPassword::DOMAIN_NAME
)
]
]
)->add(
BetterPassword::VAR_PASSWORD_REQUIREMENTS,
'collection',
[
'type' => 'text',
'allow_add' => true,
'allow_delete' => true,
'label' => $translator->trans('Password requirements description', [], BetterPassword::DOMAIN_NAME),
'label_attr' => [
'help' => $this->translator->trans(
'Please enter the password requirements description that will be displayed to your customers.',
[],
BetterPassword::DOMAIN_NAME
)
],
]
);
}
}

View File

@@ -0,0 +1,50 @@
<?php
/*************************************************************************************/
/* Copyright (c) Franck Allimant, CQFDev */
/* email : thelia@cqfdev.fr */
/* web : http://www.cqfdev.fr */
/* */
/* For the full copyright and license information, please view the LICENSE */
/* file that was distributed with this source code. */
/*************************************************************************************/
/**
* Created by Franck Allimant, CQFDev <franck@cqfdev.fr>
* Date: 03/03/2019 18:14
*/
namespace BetterPassword\Hook;
use BetterPassword\BetterPassword;
use Thelia\Core\Event\Hook\HookRenderEvent;
use Thelia\Core\Hook\BaseHook;
use Thelia\Model\Lang;
use Thelia\Model\LangQuery;
class HookManager extends BaseHook
{
public function onModuleConfigure(HookRenderEvent $event)
{
$langs = LangQuery::create()->findByActive(true);
$requirements = [];
/** @var Lang $lang */
foreach ($langs as $lang) {
$requirements[$lang->getLocale()] =
BetterPassword::getConfigValue(
BetterPassword::VAR_PASSWORD_REQUIREMENTS, '', $lang->getLocale()
);
}
$event->add(
$this->render(
'betterpassword/module-configuration.html',
[
BetterPassword::VAR_REGULAR_EXPRESSION => BetterPassword::getConfigValue(BetterPassword::VAR_REGULAR_EXPRESSION) ,
BetterPassword::VAR_PASSWORD_REQUIREMENTS => $requirements
]
)
);
}
}

View File

@@ -0,0 +1,6 @@
<?php
return array(
'Ce module vous permet d\'indiquer une expression régulière (cf. <a href="https://regex101.com">https://regex101.com</a>) que les mots de passe de vos clients devront satisfaire. Vous devrez aussi indiquer une description des contraintes à satisfaire. Cette description sera affiché à vos clients.' => 'In this module you can define a regular expression (see <a href="https://regex101.com">https://regex101.com</a>) your customer passwords must match. You must also enter a description of the requirements. This description will be displayed to your customers.',
'Demander des mots de passe sécurisés' => 'Require secure customer passwords',
);

View File

@@ -0,0 +1,6 @@
<?php
return array(
'Ce module vous permet d\'indiquer une expression régulière (cf. <a href="https://regex101.com">https://regex101.com</a>) que les mots de passe de vos clients devront satisfaire. Vous devrez aussi indiquer une description des contraintes à satisfaire. Cette description sera affiché à vos clients.' => 'Ce module vous permet d\'indiquer une expression régulière (cf. <a href="https://regex101.com">https://regex101.com</a>) que les mots de passe de vos clients devront satisfaire. Vous devrez aussi indiquer une description des contraintes à satisfaire. Cette description sera affiché à vos clients.',
'Demander des mots de passe sécurisés' => 'Demander des mots de passe sécurisés',
);

View File

@@ -0,0 +1,10 @@
<?php
return array(
'BetterPassword configuration' => 'BetterPassword configuration',
'Password requirements description' => 'Password requirements description',
'Please enter the password requirements description that will be displayed to your customers.' => 'Please enter the password requirements description that will be displayed to your customers.',
'Regular expression to match' => 'Regular expression to match',
'This is the regular expression the passwords must match.' => 'This is the regular expression the passwords must match.',
'Your password does not match the requirements : %requirement_text' => 'Your password does not match the requirements : %requirement_text',
);

View File

@@ -0,0 +1,10 @@
<?php
return array(
'BetterPassword configuration' => 'Configuration BetterPassowrd',
'Password requirements description' => 'Description des exigences',
'Please enter the password requirements description that will be displayed to your customers.' => 'Décrivez ici les exigences que les mots de passe de vos clients doivent satisfaire.',
'Regular expression to match' => 'Expression régulière à satisfaire',
'This is the regular expression the passwords must match.' => 'Il s\'agit de l\'expression régulière que les mots de passe de vos clients doivent satisfaire',
'Your password does not match the requirements : %requirement_text' => 'Votre mot de passe ne satisfait pas les conditions requises : %requirement_text',
);

View File

@@ -0,0 +1,5 @@
# Better Password
Ce module permet de contrôler que les mots de passe saisis par les clients respectent une expression régulière.
Ceci permet de forcer vos clients à utiliser des mots de passe plus sécurisés.

View File

@@ -0,0 +1,11 @@
{
"name": "cqfdev/better-password-module",
"license": "LGPL-3.0+",
"type": "thelia-module",
"require": {
"thelia/installer": "~1.1"
},
"extra": {
"installer-name": "BetterPassword"
}
}

View File

@@ -0,0 +1,68 @@
<div class="row">
<div class="col-md-12 general-block-decorator">
<div class="row">
<div class="col-md-12 title title-without-tabs">
{intl d='betterpassword.bo.default' l="Demander des mots de passe sécurisés"}
</div>
</div>
<div class="form-container">
<div class="row">
<div class="col-md-12">
{form name="betterpassword.configuration"}
<form action="{url path="/admin/module/betterpassword/configure"}" method="post">
{form_hidden_fields form=$form}
{include file = "includes/inner-form-toolbar.html"
hide_flags = true
page_url = "{url path='/admin/module/BetterPassword'}"
close_url = "{url path='/admin/modules'}"
}
{if $form_error}
<div class="row">
<div class="col-md-12">
<div class="alert alert-danger">{$form_error_message}</div>
</div>
</div>
{/if}
<div class="row">
<div class="col-md-12">
<p>
{intl d='betterpassword.bo.default' l='Ce module vous permet d\'indiquer une expression régulière (cf. <a href="https://regex101.com">https://regex101.com</a>) que les mots de passe de vos clients devront satisfaire. Vous devrez aussi indiquer une description des contraintes à satisfaire. Cette description sera affiché à vos clients.'}
<p>
</div>
<div class="col-md-6">
{render_form_field field="password_expression" value=$password_expression}
</div>
<div class="col-md-12">
{form_field field="password_requirements"}
<div class="form-group">
<label class="control-label">
{$label}<span class="required">*</span>
</label>
{loop type="lang" name="lang" active=1}
{form_field field="password_requirements" value_key=$LOCALE}
<div class="input-group" style="margin-bottom: 2px">
<input {form_field_attributes form=$form field="password_requirements" value_key=$LOCALE value=$password_requirements[$LOCALE]}>
<span class="input-group-addon">
<img src="{image file="assets/img/flags/{$CODE}.png"}" alt="{$TITLE}"
</span>
</div>
{/form_field}
{/loop}
<span class="help-block">{$label_attr.help nofilter}</span>
</div>
{/form_field}
</div>
</div>
</form>
{/form}
</div>
</div>
</div>
</div>
</div>