nayzo / NzoUrlEncryptorBundle

Symfony Bundle used to Encrypt and Decrypt data and variables in the Web application
MIT License
89 stars 19 forks source link

Encrypt FormType values #26

Closed jrswgtr closed 7 years ago

jrswgtr commented 7 years ago

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 7 years ago

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

jrswgtr commented 7 years ago

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 7 years ago

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 ?

jrswgtr commented 7 years ago

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">
jrswgtr commented 7 years ago

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,
         ));

     }
}
jrswgtr commented 7 years ago

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 7 years ago

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 7 years ago

I'm closing this request.