Bug on sanitize request

Hello!

Im with a strange behavior when I sanitize user input.
I have a custom sanitizer that transforms metadatas arrays into dynamic jsons.

Custom sanitizor:

  sanitizor.jsonInput = value => {
    const metadata = {};

    value.forEach(element => {
      const [k, v] = element;
      metadata[k] = v;
    });

    return metadata;
  };

My validator:

'use strict';

class StorePlan {
  get validateAll() {
    return true;
  }

  get sanitizationRules() {
    return {
      accept_boleto: 'to_boolean',
      accept_credit_card: 'to_boolean',
      metadata: 'json_input'
    };
  }

  get rules() {
    return {
      name: 'required',
      gateway: 'required',
      amount: 'required|number',
      trial_period_days: 'required|number',
      interval: 'required|in:day,week,month,year',
      interval_count: 'required|number',
      metadata: 'array'
    };
  }
}

My controller:

  async store({ response, request, params, session }) {
    const application = await Application.findOrFail(params.applications_id);
    const planParams = await this.planParams(request);
    const plan = await Plan.create(planParams);
    await plan.application().associate(application);

    session.flash({ alert: 'Plan created successfully' });
    response.route('Admin/Application/PlanController.edit', {
      applications_id: params.applications_id,
      id: plan.id
    });
  }

  async planParams(request) {
    return request.only([
      'name',
      'description',
      'gateway',
      'amount',
      'trial_period_days',
      'interval',
      'interval_count',
      'metadata',
      'accept_boleto',
      'accept_credit_card'
    ]);
  }

When I submit the form, the sanitize works, but it does not replace the metadata content. Instead, it merges the old content with the new content. Like this:

app_1       | {
app_1       |   name: 'Test',
app_1       |   description: 'Test description',
app_1       |   gateway: 'paypal',
app_1       |   amount: '50',
app_1       |   trial_period_days: '15',
app_1       |   interval: 'week',
app_1       |   interval_count: '1',
app_1       |   metadata: [
app_1       |     [ 'foo', 'bar' ],
app_1       |     [ 'bar', 'foo' ],
app_1       |     [ 'acme', 'inc' ],
app_1       |     foo: 'bar',
app_1       |     bar: 'foo',
app_1       |     acme: 'inc'
app_1       |   ],
app_1       |   accept_boleto: true,
app_1       |   accept_credit_card: true
app_1       | }

But if I use the validator/sanitizor in a specific field in my controller, all works fine:

  async store({ response, request, params, session }) {
    const { sanitizor } = use('Validator');
    const application = await Application.findOrFail(params.applications_id);
    const planParams = await this.planParams(request);

    if (planParams.metadata) {
      planParams.metadata = sanitizor.jsonInput(planParams.metadata);
    }

    const plan = await Plan.create(planParams);
    await plan.application().associate(application);

    session.flash({ alert: 'Plan created successfully' });
    response.route('Admin/Application/PlanController.edit', {
      applications_id: params.applications_id,
      id: plan.id
    });
  }

Output:

app_1       | {
app_1       |   name: 'Test',
app_1       |   description: 'Test description',
app_1       |   gateway: 'paypal',
app_1       |   amount: '50',
app_1       |   trial_period_days: '15',
app_1       |   interval: 'week',
app_1       |   interval_count: '1',
app_1       |   metadata: { foo: 'bar', bar: 'foo', acme: 'inc' },
app_1       |   accept_boleto: true,
app_1       |   accept_credit_card: true
app_1       | }

Package version: 4.1.0;
Node version: v12.4.0;
NPM version: 6.9.0
Github Issue: https://github.com/adonisjs/adonis-framework/issues/1094

1 Like

Thanks for creating the issue, I’ll look into it

1 Like