wheresvic / mongoose-field-encryption

A simple symmetric encryption plugin for individual fields. Dependency free, only mongoose peer dependency.
MIT License
74 stars 32 forks source link

How to use virtuals for migration? #57

Closed bluepuma77 closed 3 years ago

bluepuma77 commented 3 years ago

We are currently trying to migrate from a plain text name field to an encrypted name field. Is there a way to do this with virtuals? I would like to avoid changing the application code and continue using doc.name. It seems the virtuals are called before field-encryption can fully kick in. Using mongoose-field-encryption 3.0.6.

  1. Old code:
    
    const VisitorSchema: Schema = new Schema( {
    name: String,
    } );

2. Adding encryption, save field also encrypted:

const VisitorSchema: Schema = new Schema( { data: Object, name: String, } );

VisitorSchema.plugin(fieldEncryption, { fields: ['data'], secret: process.env.MY_DB_SECRET });

VisitorSchema.pre('save', async function() { this['data'] = { name: this['name'] } });


3. Later on, replace original field with virtual:

const VisitorSchema: Schema = new Schema( { data: Object, //name: String, } );

VisitorSchema.plugin(fieldEncryption, { fields: ['data'], secret: process.env.MY_DB_SECRET });

VisitorSchema.virtual('name') .set(function(val) { this.data.name = val; }) .get(function() { return this.data.name; });


But I get an error when trying to load a document:

TypeError: Cannot read property 'name' of undefined [in line return this.data.name;]



It seems the virtual getter is not working well with field-encryption. When adding a debug in the getter, the loaded doc has some original values from database, which are no longer included in the schema, but not (yet?) the `data` field with the encrypted data. Is there a way to fix this?
bluepuma77 commented 3 years ago

It seems this only happens when using Visitor.find().select({...}).

But using Visitor.find().select({ data:1, name:1 }) does not fix the problem.

bluepuma77 commented 3 years ago

Now it's working, I need to include the original database fields __enc_data_d and __enc_data in the select().

Is there a way to do this automatically or do I have to manually find and edit all select({...}) in my code?

wheresvic commented 3 years ago

Now it's working, I need to include the original database fields __enc_data_d and __enc_data in the select().

Is there a way to do this automatically or do I have to manually find and edit all select({...}) in my code?

Hi @bluepuma77

Happy to hear that you managed to get it working. Unfortuntately, virtuals are not supported directly by the plugin due to the extra fields that need to be created as you can see.

So yes - you would need to edit all the select in your code :(.

bluepuma77 commented 3 years ago

Thanks for the info!