In webpack add a custom plugin to change the output of the template file.

For example say there is a scenario where you would like to change the title text in the template file. Our template file is a simple Html file with a title tag. For this you can create a custom plugin, in the plugin logic fetch the html content of the template file and use simple string function like replace to change the text.

First off, you should be familiar with webpack configuration file, check out – https://webpack.js.org/ to learn about webpack. Also plugins section to add or define a plugin https://webpack.js.org/configuration/plugins/.

Below is the code example.

module.exports = {
  //...
  plugins: [
    new HtmlWebpackPlugin({
      "template": "./index.html",
      "filename": "./newIndex.html",
      ...
    }),
    new CustomTemplatePlugin(),
  ],
};

In above code we are using the html-webpack-plugin to create the template (Html) file for the webpack bundle. After this plugin is finished our custom plugin is invoked (CustomTemplatePlugin) and here we are using the events (hooks) from the HtmlWebpackPlugin to fetch the Html content and make changes.

Below is code sample for the custom plugin.

const HtmlWebpackPlugin = require("html-webpack-plugin");

function CustomTemplatePlugin(options) {
  options = options || {};
}

CustomTemplatePlugin.prototype.apply = function(compiler) {
  compiler.hooks.compilation.tap("CustomTemplatePlugin", (compilation) => {
    HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tapAsync("CustomTemplatePlugin", (htmlPluginData, cb) => {
      const fileName = htmlPluginData.plugin.options["filename"];
      if (fileName && fileName.indexOf("index") > -1) {
        htmlPluginData.html = htmlPluginData.html.replace(/Loading.../, "Hello World");
      }
      cb(null, htmlPluginData);
    });
  });
};

In above code of our custom plugin we are using getHooks static function on the HtmlWebpackPlugin to add event listener (tabAsync). In the listener we are making the change as per our requirement. We are changing the text Loading… in the title tag of our Html file to Hello World.

Below is our simple Html file.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Loading...</title>
</head>
<body>

</body>
</html>

Now when you run the webpack we should see our new Html file in the bundle i.e newIndex.html and title tag should have Hello World.

Using Nintendo gaming console outside the allowed country.

I bought a Nintendo Switch lite few months back and I went through few hassles to setup my account on Nintendo and purchase games online. In this post I am going to explain how you can setup your account outside the allowed country / timezone by Nintendo and purchase games online.

When creating the account at Nintendo I noticed that my country India was not available to be selected in the dropdown list of countries. And I also noticed that while purchasing games online my credit card was not working (accepted) because my credit card is registered in India. So I had to fix these two issues so my Nintendo account is created and then I am able to purchase games online without the messy way of purchasing the game cards!!.

Fixing problem no. 1

Choose country and timezone

When creating your account you simply choose different country and the timezone of that country. I chose US as my country and America/New York as my timezone. Also you might need to select or enter the zip code of your selected region, I choose one location in US and its zip code. You can find zip codes online.

Fixing problem no.2

Add paypal account

After creating the Nintendo account goto account settings (select user on top-right corner and click Settings button), here you will see Shop Menu (see above) on left menu list panel. Click that button.

Now you are in Show Menu page. And here you will see options to add payment methods, you can add credit card or paypal account as a payment method and while purchasing the games the added account will be charged.

Credit card payment option did not work for me. So what I did is, I created a paypal account and in my paypal account added / linked my credit card. Now in Nintendo Shop Menu page I have added paypal as my payment method, it worked, I purchased lot of games online from Nintendo without any issues.

Nintendo is going to fetch the payment from your paypal account and the paypal account in turn bills your credit card. That is how it works.

Hope this post helps someone!.

Using bcrypt to store password in NodeJS.

Before starting the post I would like to assume few things:

  1. You have knowledge about NodeJS.
  2. You have setup sample NodeJS app using express and mongoDB

In case you have no idea what I am talking about then its best to know about them. Few links below will help.

Now let’s get to post…

Install bcryptjs:

$npm install bcryptjs

Hash your password:

Instead of storing the passwords in plain text we will use a method called hash in bcryptjs to generate hash. Hashing or password hashing is a process used to turn or transform your original plain string into another encrypted string. And this new string or hash is stored in DB. Even if someone finds the hash they won’t be able to login. This is the most secure way.

bcrypt.hash(myPassword, 10)

I would prefer you spend some time to read more about the plugin here.

Below is my sample code which creates a user and store the hash for password.

const bcrypt = require("bcryptjs");

exports.createUser = (req, res, next) => {
  bcrypt.hash(req.body.password, 10).then(hash => {
    const user = new User({
      username: req.body.username,
      password: hash,
      displayName: req.body.displayName,
      roles: req.body.roles,
    });
    user
        .save()
        .then(result => {
          res.status(201).json({
            message: "User created!",
            result: result
          });
        })
        .catch(err => {
          res.status(500).json({
            message: "Invalid authentication credentials!",
            error: err
          });
        });
  });
};

Below is the sample code for user login.

const bcrypt = require("bcryptjs");
const User = require("../models/user");

exports.userLogin = (req, res, next) => {
  let fetchedUser;
  User.findOne({ username: req.body.username })
      .then(user => {
        if (!user) {
          return res.status(401).json({
            message: "Auth failed"
          });
        }
        fetchedUser = user;
        return bcrypt.compare(req.body.password, user.password);
      })
      .then(result => {
        if (!result) {
          return res.status(401).json({
            message: "Authentication failed, please check your login credentials."
          });
        }
        res.status(200).json({
          message: "Login success."
        });
      })
      .catch(err => {
        return res.status(401).json({
          message: "Invalid authentication credentials!",
          error: err
        });
      });
};

Here we use the compare method in bcrypt to check if the entered user password matches with the stored password. It’s valid only if they match. You can also observe I am returning few responses with status codes at each step of the way.

Below is the schema for user just in case.

const mongoose = require("mongoose");
const uniqueValidator = require("mongoose-unique-validator");

const userSchema = mongoose.Schema({
  username: { type: String, required: true, unique: true },
  password: { type: String, required: true },
  displayName: { type: String },
  roles: { type: [String], required: true }
});

userSchema.plugin(uniqueValidator);

module.exports = mongoose.model("User", userSchema);

Define schema, apply plugin and more in Mongoose.

I’ve been learning Mongoose and would like to share few notes. Let’s say we have Invoice schema like below defined in mongoose.

const mongoose = require("mongoose");

const invoiceSchema = mongoose.Schema({
  creationDate: {type: Date, default: Date.now},
  description: {type: String, required: true},
  amount: {type: String, required: true}
});

To this schema I would like to add a new property / key / field that will define the status of the invoice, and this new property takes predefined values, like, an enum.

status: {type: String, enum: ["New", "Assigned", "Completed"]}

Above status is the new property added to my invoice scheme. And mongoose creates a validator that checks if the value is in the given array of strings.

In a real world case we would like to know who created an invoice. For this we need to store the user id (invoice creator id) for each document, given that we have User schema already defined. Below is the property creator that we can define for such cases…

creator: {type: mongoose.Schema.Types.ObjectId, ref: "User", required: true}

Here the property creator is of type ObjectId and it refers to User schema.

Every invoice will have a number, and let’s say we need to maintain an auto-increment number for each document created that will serve as an invoice number. For this we can make use of plugins, we can either create a plugin ourselves or use an existing one. I found one plugin for our use-case called mongoose-auto-increment. Let us use this package as our plugin.

const autoIncrement = require("mongoose-auto-increment");
...
autoIncrement.initialize(mongoose.connection);
invoiceSchema.plugin(autoIncrement.plugin, { model: 'Invoice', field: 'orderNo', startAt: 1 });

Above code will add a new property called orderNo to our schema and will use the plugin mongoose-auto-increment to auto-increment (startAt is set to 1 so we start from 1 … ) the property every time we insert a new document of this type.

This is all we wanted for now!, let us look at the full schema now.

const mongoose = require("mongoose");
const autoIncrement = require("mongoose-auto-increment");

const invoiceSchema = mongoose.Schema({
  creationDate: {type: Date, default: Date.now},
  description: {type: String, required: true},
  amount: {type: String, required: true},
  status: {type: String, enum: ["New", "Assigned", "Completed"]},
  creator: {type: mongoose.Schema.Types.ObjectId, ref: "User", required: true}
});

autoIncrement.initialize(mongoose.connection);
invoiceSchema.plugin(autoIncrement.plugin, { model: 'Invoice', field: 'orderNo', startAt: 1 });

module.exports = mongoose.model("Invoice", workOrderSchema);

Note: To use the plugin mongoose-auto-increment you first need to install it $npm install mongoose-auto-increment.

Install npm packages on Elastic Beanstalk aws service instance globally.

First off I am going to assume three things…

  1. You know how to create an Elastic Beanstalk aws service instance with Node.js as the platform.
  2. You know how to create a key file (.pem) on aws console.
  3. You know how to login (ssh) to the instance using the key file.

Now the question, why would you need to install npm packages after the setup or after creating the instance. During the setup when you select the option to upload the source code (.zip) you are providing the package.json (npm packages are defined here) file from which all the packages are installed and available in node_modules. But what if some package is required to be installed at global level.

Elastic Beanstalk – Platform – Node.js

Below are the steps I used to install a package called html-pdf globally to the instance.

  1. Login to the instance.
    • $ssh -i pem/awsinstancekeypairname2.pem ec2-user@INSTANCE_NAME.com
  2. Switch to root user.
    • $sudo su
  3. Set path to node location
    • $export PATH=$PATH:/opt/elasticbeanstalk/node-install/node-v10.17.0-linux-x64/bin/
    • Note: Above node version and path of the node on you elastic beanstalk instance might be different.
  4. Install html-pdf package globally.
    • $npm install -g html-pdf
  5. Now link the installed package.
    • $npm link html-pdf
  6. Restart the app server / instance and you are done.

Fix for ‘Host key verification failed’ error.

When we login to a host using ssh we might come across the error ‘Host key verification failed’. If you see additional message saying the ‘host key for XX.XX.XX has changed’ then the fix i am giving will work for you.

You see this error because the key of the host system is basically changed and this new key on the host system does not match with the one that is locally saved.

Error on terminal

The fix is to remove the host from the known hosts list (/.ssh/known_hosts) on your local system. Below is the command.

$ssh-keygen -R XX.XX.XX

After removing the host you can try login again. $ssh userName@XX.XX.XX and you are logged in.

Note: XX.XX.XX – Is the host DNS, like, 10.10.10.10. And the fix works only on Mac.