Installing npm modules globally without sudo

I needed to install pm2 globally and run it as non root. This meant installing it with npm without using the sudo command. However, when you do this npm will throw an error.

“Error: EACCES: permission denied”

The npm documentation does provide a solution that works, which has a caveat.

  1. Make a directory for global installations:
    mkdir ~/.npm-global
  2. Configure npm to use the new directory path:
    npm config set prefix '~/.npm-global'
  3. Open or create a ~/.profile file and add this line:
    export PATH=~/.npm-global/bin:$PATH
  4. Back on the command line, update your system variables:
    source ~/.profile

As a side note, an easier way to execute step 3 is:

echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.profile

When I initially executed these steps it worked. However, after logging out and in again the pm2 command was no longer available. It turns out that on login the .bash_profile file is loaded instead of the .profile. Actually bash will try loading ~/.bash_profile, ~/.bash_login and ~/.profile, in that order. Once it finds one of them it will not try and load any of the others. After adding the statement to .bash_profile it worked like a dream.

echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bash_profile

Hope this helps someone.

Advertisements

Override module loaded by require

I was using the module redact-secrets with Winston logger. This module makes sensitive data like passwords unreadable in logfiles. Very cool and handy module. It makes use of another module is-secret that contains a collection of patterns to determine what sensitive data is. One piece of sentive data was missing from is-secret: pass. I could fix it on my side, but I prefer the original GitHub project to be updated so others can also profit from it. So I submitted an issue on GitHub. While waiting for the fix I needed to continue with my development work. So I used another handy module override-require. This module overrides the resolution logic of require. So you can use it to override a dependency of a module. I used it in the following to overrule is-secret used by redact-secrets.

const overrideRequire = require('override-require');

// Check if a request needs to be overridden
const isOverride = (request) => {
return request === 'is-secret';
};

// If isOverride is true, load the module with the overridden module
const resolveRequest = (request) => {
return require('./overrule/is-secret');
};

// Initialize overide-require
const restoreOriginalModuleLoader = overrideRequire(isOverride, resolveRequest);

const { createLogger, format, transports } = require('winston');
// When redacts-secrets is loaded override-require will kickin and load our own module
const redact = require('redact-secrets')('******');
const fs = require('fs');
const path = require('path');

// Disable override require
restoreOriginalModuleLoader();

 

That’s it. Pretty cool isn’t it?

Webstorm not recognising Vuetify component html tags

Recently I moved from VS Code to Webstorm. What a brilliant IDE. It really improved my development flow. One thing that has been irritating me is that the Vuetify component html tags are not recognised, which results in a s**t load of warning messages of unrecognised html tags.

After Googling around I found an issue on the Vuetify GitHub Issues that provides a simple workaround. All you need to do is create a file somewhere in the project that describes the Vuetify components. You don’t need to import the file. It just has to be accessible to Webstorm so that it can be analysed.

There is a fix in the works for the Vuetify api-generator that provides this file out of the box. Just checkout the Javascript and Typescript files.

I placed the Javascript file in my plugin directory naming it vuetify-fake-components-for-webstorm.js. After that all the warnings of unrecognised html tags disappeared like magic. Wooho!

Using Git with SSH key on Windows

Just a quick write up as reminder how to generate a SSH key on Windows and use it with Git. Git comes with OpenSSH which includes ssh-keygen. Of course you can use Putty to generate SSH keys, but why not do it the quick and easy way with Git? If you use Putty you need to convert the generated key from Putty format to the standard SSH format.

Okay lets get started. Follow along with the following steps.

1. Make Open SSH utilities accessible

Add the Git directory containing the OpenSSH command line utilities to the Windows Path. They are installed in the following location.

C:\Program Files\Git\usr\bin

You can do this the traditional way using Windows Control Panel executing the following steps.

  • Pressing the Windows key to open up the Start Menu
  • Search for “advanced system settings” (just start typing)

Alternatively you can browse through the Control Panel.

  • Select System and Security
  • System
  • Click on the Advanced system settings hyperlink in the left hand pane

Or do it the easy way if you have Rapid Environment Editor (RapidEE) installed. Use the following command line from a shell with administrative privileges to add it to the system wide path (for all users) or leave out the -M flag to add the variable to the user path.

rapidee -A -M Path "C:\Program Files\Git\usr\bin"

2. Generate the SSH key pair

NOTE: If you want Git to work with the generated SSH key pair without any further configuration then accept the default location and name of the SSH key pair.

An SSH key consists of a private and public key. The private key should be stored safely, the public key can be shared with others. Don’t forget to set a passphrase for your private key. The passphrase prevents unauthorised usage of the private key by protecting the key itself with a password. Although the directory holding the private keys should be inaccessible to other users, the root user of the system, or anyone who can access the private key can copy and use it if not protected by a passphrase.To add a passphrase to a key just type it when prompted during the key generation process. Keep in mind that the password must be at least 5 characters long. A good passphrase should be at least 10 characters long, and consist of random upper and lower case letters, numbers and symbols.

Generate the SSH key pair with the following command.

ssh-keygen -t rsa -b 4096 -C "nidkil-git-key"

The -t is the key type, -b is the key length (the higher the more secure) and -C is a comment that is added to the key which makes it easier to identify. The comment is added to the end of the key. Don’t believe me? Open the public key file and you will see your comment. Handy isn’t it?

3. Use the SSH public key

If you did not change the default location and name, the SSH key pair can be found in the directory .ssh in the users home directory.

That’s all fooks. Have fun.

Accessing home folders from Windows Subsystem for Linux in Explorer

Are you running Windows Subsystem for Linux (WSfL)? Ever wondered where the home folders are stored so that you can access them from Explorer? Seek no further for here is the answer.

Every distribution has it’s own location. They can be found under:

%LOCALAPPDATA%\Packages

For Ubuntu 18.04 you can find the home folders in the following location:

%LOCALAPPDATA%\Packages\CanonicalGroupLimited.Ubuntu18.04onWindows_79rhkp1fndgc\LocalState\rootfs\home

Enjoy!

Testing Mongoose plugin with Jest and shared data

Grrrr just spent the better half of 2 hours trying to figure out why my Jest tests were not working for a Mongoose plugin I’m developing. It turns out that the schema configuration I was sharing between the tests was the culprit.

let Mongoose = require('mongoose');
let Schema = Mongoose.Schema;
const _ = require('lodash');
var mongooseI18n = require('../src/mongoose/mongoose-i18n-localize');

Mongoose.set('debug', true);

const simpleSchemaConfig = {
  firstName: { type: String, i18n: true, required: true },
  lastName: { type: String, i18n: false, required: true }
};

describe('Mongoose i18n localize', () => {
  beforeEach(() => {
    // Clear compiled models to avoid OverwriteModelError
    Mongoose.models = {};
  });
  
  it('should throw an exception if the locales array is not defined', () => {
    const SimpleTestSchema = new Schema(simpleSchemaConfig);
    expect(() => {
      SimpleTestSchema.plugin(mongooseI18n, {
        defaultLocale: 'nl',
        allLocalesRequired: false
      });
    }).toThrow('The required option locales array not provided or empty');
  });

  it('should throw an exception if the locales array is an empty array', () => {
    const SimpleTestSchema = new Schema(simpleSchemaConfig);
    expect(() => {
      SimpleTestSchema.plugin(mongooseI18n, {
        locales: [],
        defaultLocale: 'nl',
        allLocalesRequired: false
      });
    }).toThrow('The required option locales array not provided or empty');
  });

  ...

});

The plugin makes changes to the schema configuration and these changes were made to the shared config. The fix I used was to make a copy of the shared config with lodash’s cloneDeep function. The only change I needed to make was the schema initialization.

const SimpleTestSchema = new Schema(_.cloneDeep(simpleSchemaConfig));

Now my tests run like a charm 🙂

Bonus

When I initially ran into the above problem, I was also initializing the schema globally. I thought that was the problem, so I moved the following statement to each test case.

const SimpleTestSchema = new Schema(simpleSchemaConfig);

That caused the exception OverwriteModelError, because I was trying to initialize a compiled model. The fix for this problem was to remove all models between test cases using beforeEach. The following code does the trick.

beforeEach(() => {
  // Clear compiled models to avoid OverwriteModelError
  Mongoose.models = {};
});

Hope this helps someone.

Change root password Windows Subsystem for Linux

Today I was setting up Windows Subsystem for Linux and wanted to change to the root user using the command:

su -

I was prompted for the password, but had no idea what it was. So I needed to figure out another way of switching to the root user instead of prefixing every command with sudo. Did I say switch and prefix and sudo? O yes, stupid me.

sudo su

Don’t forget to exit once you are done. And be careful not to wrech havoc while working under the root account. Have fun!