mongoose-field-encryption icon indicating copy to clipboard operation
mongoose-field-encryption copied to clipboard

Model is not a constructor, TypeError

Open doverradio opened this issue 3 years ago • 1 comments

Hello,

I am trying to use your package to encrypt a specific field of my schema on a collection named Customers.

However, upon first run, it got an error: TypeError: Customers is not a constructor

I am using express.js for my endpoints.

Error message:

createCustomer e:  TypeError: Customers is not a constructor
    at exports.createCustomer (C:\Users\User\Desktop\project\backend\controllers\customers.js:12:26)
    at Layer.handle [as handle_request] (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\route.js:137:13)
    at Route.dispatch (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\layer.js:95:5)
    at C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:281:22
    at Function.process_params (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:335:12)
    at next (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:275:10)
    at Function.handle (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:174:3)
    at router (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:47:12)
    at Layer.handle [as handle_request] (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:317:13)
    at C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:284:7
    at Function.process_params (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:335:12)
    at next (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:275:10)
    at C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:635:15
    at next (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:260:14)
    at Function.handle (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:174:3)
    at router (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:47:12)
    at Layer.handle [as handle_request] (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:317:13)
    at C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:284:7

My model:

const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const { ObjectId } = mongoose.Schema;
const mongooseFieldEncryption = require("mongoose-field-encryption").fieldEncryption;

const customersSchema = new mongoose.Schema(
  {
    firstName: {
      type: String,
      default: ''
    },
    lastName: {
      type: String,
      default: ''
    },
    fullName: {
      type: String,
      default: ''
    },
    streetAddress: {
      type: String,
      default: ''
    },
    extendedAddress: {
      type: String,
      default: ''
    },
    city: {
      type: String,
      default: ''
    },
    state: {
      type: String,
      default: ''
    },
    zip: {
      type: String,
      default: ''
    },
    customerType: {
      type: String,
      default: null
    },
    user: {
      type: ObjectId,
      ref: "User"
    },
    nextActivity: {
      type: String,
      default: null
    },
    total: { type: Number },
    status: {
      type: String,
      default: "Sales Order",
      enum: [
        "Sales Order", 
        "Quotation",
      ] // enum means string objects
    },
  },
  { timestamps: true }
);

var encKey = process.env.SOME_32BYTE_BASE64_STRING;

customersSchema.plugin(mongooseFieldEncryption, { 
  fields: ["streetAddress", "fullName"], 
  secret: encKey, // "some secret key",
  saltGenerator: function (secret) {
    return "1234567890123456"; 
  },
});

mongoose.model("Customers", customersSchema, 'customers');

My controller method:

const Customers = require('../models/customers')
const log = console.log


exports.createCustomer = async ( req, res ) =>
{
    log( `Beginning createCustomer! Here's req.body: `, req.body )
    let a = {}
    try {
        a.new_customer = new Customers( req.body )
        a.new_customer_doc = await a.new_customer.save().catch( err => log( `a.new_customer.save err: `, err ) )
        res.json( a.new_customer_doc )
    } catch ( e ) {
        log( `createCustomer e: `, e )
        res.status( 400 ).json( { error: e } )
    }
}

My routes file:

const express = require("express");
const router = express.Router();

const {
    createCustomer,
} = require( "../controllers/customers" )

// generate customer
router.post( "/customers/createnewcustomer", createCustomer )

module.exports = router;

My test JSON data going into Postman:

{
    "firstName": "Bob",
    "lastName": "Saget",
    "fullName": "Bob Saget",
    "streetAddress": "389 N. Palm Dr.",
    "extendedAddress": "Unit 3",
    "city": "Palm Beach",
    "state": "FL",
    "zip": "40888",
    "customerType": "ebay",
    "user": "6020daa83294c92c281ef313",
    "nextActivity": "Check if encryption worked",
    "total": 1,
    "status": "Sales Order"
}

Here is the complete response shown in the console:

Beginning createCustomer! Here's req.body:  {
  firstName: 'Bob',
  lastName: 'Saget',
  fullName: 'Bob Saget',
  streetAddress: '389 N. Palm Dr.',
  extendedAddress: 'Unit 3',
  city: 'Palm Beach',
  state: 'FL',
  zip: '40888',
  customerType: 'ebay',
  user: '6020daa83294c92c281ef313',
  nextActivity: 'Check if encryption worked',
  total: 1,
  status: 'Sales Order'
}
createCustomer e:  TypeError: Customers is not a constructor
    at exports.createCustomer (C:\Users\User\Desktop\project\backend\controllers\customers.js:12:26)
    at Layer.handle [as handle_request] (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\route.js:137:13)
    at Route.dispatch (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\layer.js:95:5)
    at C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:281:22
    at Function.process_params (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:335:12)
    at next (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:275:10)
    at Function.handle (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:174:3)
    at router (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:47:12)
    at Layer.handle [as handle_request] (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:317:13)
    at C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:284:7
    at Function.process_params (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:335:12)
    at next (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:275:10)
    at C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:635:15
    at next (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:260:14)
    at Function.handle (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:174:3)
    at router (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:47:12)
    at Layer.handle [as handle_request] (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:317:13)
    at C:\Users\User\Desktop\project\backend\node_modules\express\lib\router\index.js:284:7
POST /api/customers/createnewcustomer 400 22.531 ms - 12

Even further, I tried to add this code which did nothing to change the error:

// function to generate salt
var genRandomString = function(length){
  return crypto.randomBytes(Math.ceil(length/2))
          .toString('hex') /** convert to hexadecimal format */
          .slice(0,length);   /** return required number of characters */
};

var sha512 = function(password, salt){
  var hash = crypto.createHmac('sha512', salt); /** Hashing algorithm sha512 */
  hash.update(password);
  var value = hash.digest('hex');
  return {
      salt:salt,
      passwordHash:value
  };
}; 

function saltHashPassword(userpassword) {
  var salt = genRandomString(16); /** Gives us salt of length 16 */
  var passwordData = sha512(userpassword, salt);
  console.log('UserPassword = '+userpassword);
  console.log('Passwordhash = '+passwordData.passwordHash);
  console.log('\nSalt = '+passwordData.salt);
}

customersSchema.plugin(mongooseFieldEncryption, { 
  fields: ["streetAddress", "fullName"], 
  secret: encKey, // "some secret key",
  saltGenerator: function ( secret ) {
    var salt = genRandomString(16); /** Gives us salt of length 16 */
    console.log( `salt: `, salt )
    var data = sha512(secret, salt);
    console.log( `data: `, data )
    return data
  },
});

What am I doing wrong?

doverradio avatar Apr 27 '22 23:04 doverradio

Hi @doverradio

Sorry for the delay in responding to this. From the error TypeError: Customers is not a constructor, it seems that your Customers class has not been defined properly. If you can post the code for this, I could perhaps advise further.

wheresvic avatar May 03 '22 07:05 wheresvic