nayzo/NzoUrlEncryptorBundle

Encrypt FormType values

Closed this issue · 8 comments

I would love to have my forms to automatically encrypt and decrypt my entity ID's (in EntityType choice fields), so the ID's stay hidden to the client.

Is there any way of achieving this with this bundle?

nayzo commented

How are you plaining to keep the ID hidden from the client by using the EntityType ?

I don't want that users can see the id's of entities. Therefore I encrypt them with your bundle.

I want to encrypt the ID's when the EntityType gets filled. So the rendered form field (select, radio or checkbox inputs) has encrypted id's as values.

When the form gets submitted the value has to be decrypted for Symfony to handle the form correctly.

nayzo commented

I still can't get how could someone see the ID of the entity from the formType generated in the front.
Could you elaborate more or send me a code snippet or an example ?

The rendered HTML contains the ID's of the entities. They are not directly visible on the page, but with very little effort you can retrieve them.

<input type="radio" id="crop_profile_2" name="crop[profile]" required="required" value="2">
<input type="radio" id="crop_profile_8" name="crop[profile]" required="required" value="8">
<input type="radio" id="crop_profile_12" name="crop[profile]" required="required" value="12">

This is the FormType. the last part of function buildForm() is where I fill the ProfileChoiceType (extends EntityType)

class CropType extends AbstractType
{
	private $tokenStorage;

    public function __construct(TokenStorageInterface $tokenStorage)
    {
        $this->tokenStorage = $tokenStorage;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
	$user = $this->tokenStorage->getToken()->getUser();
        if (!$user) {
            throw new \LogicException('The CropType cannot be used without an authenticated user!');
        }

        $builder
			->add('sourceFile', FileType::class, [
				'required' => false,
				'label' => false,
				'attr' => ['hidden' => true],
			])
			->add('sourceWidth',  NumberType::class, [
				'required' => true,
				'label' => false,
				'attr' => ['hidden' => true],
			])
			->add('newWidth',  NumberType::class, [
				'required' => true,
				'label' => false,
				'attr' => ['hidden' => true],
			])
			->add('positionX', NumberType::class, [
				'required' => true,
				'label' => false,
				'attr' => ['hidden' => true],
			])
			->add('positionY', NumberType::class, [
				'required' => true,
				'label' => false,
				'attr' => ['hidden' => true],
			])
		;

		$builder->addEventListener(
			FormEvents::PRE_SET_DATA,
		   	function (FormEvent $event) use ($user) {
				$form = $event->getForm();

			   	$formOptions = array(
					'class'         => Profile::class,
				   	'query_builder' => function (EntityRepository $er) use ($user) {
						// build a custom query
					   	$user_id = $user->getId();
					   	$qb = $er->createQueryBuilder('p');
					   	return $qb
							->join('p.profileCategory', 'c')
							->andWhere($qb->expr()->eq('p.user', $user_id))
							->orWhere($qb->expr()->eq('c.global', true))
							->orderBy('c.global', 'ASC')
							->addOrderby('p.profileCategory', 'DESC')
						;
				   	},
				   	'label' => false,
	   			   	'expanded' => true,
	   			   	'allow_extra_fields' => true,
	   			   	'attr' => [
	   					'class' => 'profile-list'
	   				],
			   );

			   $form->add('profile', ProfileChoiceType::class, $formOptions);
		   }
	   );
    }

    public function configureOptions(OptionsResolver $resolver)
    {
		$resolver->setDefaults(array(
		 	'data_class' => Crop::class,
		 ));

     }
}

I am thinking about using a Doctrine EvenListener class to encrypt the id on load and decrypt the id pre update. This way the ID's are always encrypted when sent to the client, and always decrypted before stored.

For the ParamConverter annotation to work I can use the ParamDecryptor annotation.

http://symfony.com/doc/current/doctrine/event_listeners_subscribers.html

class EntityEncryptionListener
{

    /**
     * Decrypt entity ID before it is updated
     * @param  PreUpdateEventArgs $args
     */
    public function preUpdate(PreUpdateEventArgs $args)
    {
        $entity = $args->getEntity();
         // implement decrypt ID
    }

    /**
     * Encrypt entity ID after it is loaded
     * @param  LifecycleEventArgs $args
     */
    public function postLoad(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();
	// implement encrypt ID
    }
}
nayzo commented

Yes, this coud be a way to do it, you have to inject the encryptor service in your FormType and call it in the EvenListener.

nayzo commented

I'm closing this request.