Categories
JavaScript JavaScript Basics

Using the Javascript Conditional Operator

The JavaScript conditional operator is a basic building block of JavaScript programs.

The conditional operator is also called the ternary operator.

It lets us write expression that returns one thing if a given condition it truthy and return something else otherwise.

The conditional operator is denoted by the ? operator.

We can use it as follows:

const foo = condition ? 'foo' : 'bar';

In the code above, if condition is truthy, then 'foo' is returned. Otherwise, 'bar' is returned.

Then the returned value is assigned to the foo variable.

The code is above is short for:

if (condition) {
  return 'foo';
}
else {
  return 'bar';
}

As we can see, the code above is much longer than using the conditional operator.

Since it’s save so much typing and space on the page, we should use the conditional operator instead of using if statements if we want to write code that returns one thing if a given condition is truthy and something else otherwise.

Categories
JavaScript JavaScript Basics

Introduction to JavaScript Strict Mode

JavaScript is a very forgiving language. It’s easy to write code that runs but has mistakes in it.

In this article, we’ll look at the benefits of using the strict mode directive.

Add Use Strict Mode Directive in Our Scripts

If we’re using old-school JavaScript script files, then we should add the 'use strict' directive into the top of our script.

Strict mode eliminates lots of silent errors by changing them to throw errors.

It also fixes mistakes that make optimizing our JavaScript code hard to increase their performance.

Also, it bans syntax that may be used in future JavaScript versions. Keywords like class can’t be used to declare variables, for example.

Strict mode can be applied to the whole script by putting the directive at the top or just in the function level by putting it in functions.

However, we should just apply it everywhere since it brings lots of benefits.

For instance, we can’t declare variables accidentally with 'use strict':

'use strict';
x = 1;

Since we have the 'use strict' directive on top of our script, we’ll get an error with the x = 1 expression since we haven’t declared x yet.

Without strict mode, this would create a global variable called x and assign 1 to it and pollute the global scope.

That isn’t good because it may overwrite another global variable with the same name.

Also, we can assign values to another global value like undefined or Infinity:

With strict mode on, code like the following will throw a TypeError:

var undefined = 1;
var Infinity = 1;

Assigning values to a non-writable property will also fail with a TypeError thrown:

var obj = {};
Object.defineProperty(obj, 'foo', { value: 42, writable: false });
obj.foo = 9;

We also wouldn’t be able to add properties that has preventExtensions called on it to prevent that:

var obj = {};
Object.preventExtensions(obj);
obj.foo = 'a';

The code above would throw a TypeError.

Attempting to delete undeletable properties will also throw an error. If we write something like:

'use strict';
delete Object.prototype;

Then we’ll get a TypeError.

Strict mode also requires function parameters to be unique. For instance, if we write:

'use strict';
function add(a, a, c) {  
  return a + a + c; 
}

Then we’ll get an ‘Uncaught SyntaxError: Duplicate parameter name not allowed in this context’ error since we have JavaScript strict mode on.

Also, it prevents numbers with a leading 0 from being used. The leading zero for octal numbers is rarely used and developers often assume that it’s still a decimal number.

Therefore if we have the following the strict mode throws an error:

'use strict';
var sum = 015 + 222;

If we run that, we get ‘Uncaught SyntaxError: Octal literals are not allowed in strict mode.’

The with statement is prohibited in strict mode. With strict mode, confusing code like this is prohibited:

'use strict';
var x = 17;
with(obj) {
  console.log(x);
}

The code above is confusing because x can either be obj.x or just x. It’s hard to tell what it’s referring to.

With strict mode on as we have above, we get ‘Uncaught SyntaxError: Strict mode code may not include a with statement’.

Doing anything to arguments or eval will also return syntax errors, so code like the following:

'use strict';
eval = 'foo';
arguments++;

Then we get ‘Uncaught SyntaxError: Unexpected eval or arguments in strict mode’ when we run the code above since we have JavaScript strict mode on.

We shouldn’t use these entities regardless of whether JavaScript strict mode is on, so it’s good that strict mode prevents expressions like these from running at least.

With strict mode on, the this value passed into call, apply, or bind aren’t boxed into an object.

Therefore, the original value is preserved if we pass in a primitive value. For instance, if we have:

'use strict';
function fn() {  
  return this;
}
console.log(fn.call(1) === 1);

Then we get 1 returned from fn instead of new Number(1), so we get that the console log output returns true.

Strict mode is enabled automatically for modules so we don’t need the directive on top of our code.

Conclusion

With so many benefits to strict mode, we should always enable it in old-school scripts.

If we use JavaScript modules, then it’s enabled by default, so we don’t have to worry about it.

We just have to put 'use strict' on top of all our scripts.

Categories
JavaScript Nodejs

Using the Node.js OS Module (Part 1)

The Node.js OS module has many useful utility functions for getting information about the computer system that the OS module’s program is running on. It can provide information about hardware such as CPUs, endianness, the home directory, IP address, hostname, the platform the program is running on, system uptime, information about the currently logged in user and more.

We can use the OS module by writing const os = require('os'); at the top of a file. There are many useful properties in the OS module. Below are some of the useful properties in the OS module:

os.EOL

The os.EOL property is a string constant that has the operating system specific end of line marker. For POSIX operating system, it’s \n and for Windows, it’s \r\n . We can use it like the following code as an example:

console.log(`End of line market is ${os.EOL}`)

Then we get:

'End of line market is \n'

os.arch()

The os.arch() function returns a string that tells us the operating system CPU architecture that the Node.js binary is compiled on. Possible values are 'arm', 'arm64', 'ia32', 'mips', 'mipsel', 'ppc', 'ppc64', 's390', 's390x', 'x32', and 'x64'. It’s the same as the process.arch function. For example, we can use it like in the following code:

console.log(`Node.js is built in ${os.arch()}`)

The we get:

'Node.js is built in x64'

if Node.js was compiled on an x64 system

os.constants

The os.constants property has a collection of constants for error codes, process signals, etc. The following are the constants from os.constants :

Signal Constants

  • SIGHUP — signal sent to indicate when a controlling terminal is closed or a parent process exits.
  • SIGINT — signal sent to indicate when a user wishes to interrupt a process ((Ctrl+C)).
  • SIGQUIT — signal sent to indicate when a user wishes to terminate a process and perform a core dump.
  • SIGILL — signal sent to a process to notify that it has attempted to perform an illegal, malformed, unknown, or privileged instruction.
  • SIGTRAP — signal sent to a process when an exception has occurred.
  • SIGABRT — signal sent to a process to request that it abort.
  • SIGIOT — same as SIGABRT
  • SIGABRTSIGBUS — signal sent to a process to notify that it has caused a bus error.
  • SIGFPE — signal sent to a process to notify that it has performed an illegal arithmetic operation.
  • SIGKILL — signal sent to a process to terminate it immediately.
  • SIGUSR1 SIGUSR2 — signal sent to a process to identify user-defined conditions.
  • SIGSEGV — signal sent to a process to notify of a segmentation fault.
  • SIGPIPE — signal sent to a process when it has attempted to write to a disconnected pipe.
  • SIGALRM — signal sent to a process when a system timer elapses.
  • SIGTERM — signal sent to a process to request termination.
  • SIGCHLD — signal sent to a process when a child process terminates.
  • SIGSTKFLT — signal sent to a process to indicate a stack fault on a co-processor.
  • SIGCONT — signal sent to instruct the operating system to continue a paused process.
  • SIGSTOP — signal sent to instruct the operating system to halt a process.
  • SIGTSTP — signal sent to a process to request it to stop.
  • SIGBREAK — signal sent to indicate when a user wishes to interrupt a process.
  • SIGTTIN — signal sent to a process when it reads from the teletypewriter while in the background.
  • SIGTTOU — signal sent to a process when it writes to the teletypewriter while in the background.
  • SIGURG — signal sent to a process when a socket has urgent data to read.
  • SIGXCPU — signal sent to a process when it has exceeded its limit on CPU usage.
  • SIGXFSZ — signal sent to a process when it grows a file larger than the maximum allowed.
  • SIGVTALRM — signal sent to a process when a virtual timer has elapsed.
  • SIGPROF — signal sent to a process when a system timer has elapsed.
  • SIGWINCH — signal sent to a process when the controlling terminal has changed its size.
  • SIGIO — signal sent to a process when I/O is available.
  • SIGPOLL — same as SIGIO
  • SIGIOSIGLOST — signal sent to a process when a file lock has been lost.
  • SIGPWR — signal sentto a process to notify of a power failure.
  • SIGINFO — same as SIGPWR
  • SIGPWRSIGSYS — signal sent to a process to notify of a bad argument.
  • SIGUNUSED — same as SIGSYS

Error Constants for POSIX Systems

The following are constants for error indicators that are raised in POSIX systems.

  • E2BIG — list of arguments is longer than expected.
  • EACCES — the operation did not have sufficient permissions.
  • EADDRINUSE — the network address is already in use.
  • EADDRNOTAVAIL — the network address is currently unavailable for use.
  • EAFNOSUPPORT — he network address family is not supported.
  • EAGAIN — there is currently no data available and to try the operation again later.
  • EALREADY — the socket already has a pending connection in progress.
  • EBADF — file descriptor is not valid.
  • EBADMSG — invalid data message.
  • EBUSY — device or resource is busy.
  • ECANCELED — an operation was canceled.
  • ECHILD — there are no child processes.
  • ECONNABORTED — network connection has been aborted.
  • ECONNREFUSED — network connection has been refused.
  • ECONNRESET — network connection has been reset.
  • EDEADLK — resource deadlock has been avoided.
  • EDESTADDRREQ — a destination address is required.
  • EDOM — an argument is out of the domain of the function.
  • EDQUOT — the disk quota has been exceeded.
  • EEXIST — the file already exists.
  • EFAULT — invalid pointer address.
  • EFBIG — the file is too large.
  • EHOSTUNREACH — the host is unreachable.
  • EIDRM — the identifier has been removed.
  • EILSEQ — an illegal byte sequence encountered.
  • EINPROGRESS — an operation is already in progress.
  • EINTR — a function call was interrupted.
  • EINVAL — an invalid argument was provided.
  • EIO — unspecified I/O error.
  • EISCONN — the socket is connected.
  • EISDIR — the path is a directory.
  • ELOOP — too many levels of symbolic links in a path.
  • EMFILE — there are too many open files.
  • EMLINK — there are too many hard links to a file.
  • EMSGSIZE — the provided message is too long.
  • EMULTIHOP — a multihop was attempted.
  • ENAMETOOLONG — he filename is too long.
  • ENETDOWN — the network is down.
  • ENETRESET — the connection has been aborted by the network.
  • ENETUNREACH — the network is unreachable.
  • ENFILE — too many open files in the system.
  • ENOBUFS — no buffer space is available.
  • ENODATA — no message is available on the stream head read queue.
  • ENODEV — that there is no such device.
  • ENOENT — there is no such file or directory.
  • ENOEXEC — an exec format error.
  • ENOLCK — there are no locks available.
  • ENOLINK — a link has been severed.
  • ENOMEM — there is not enough space.
  • ENOMSG — there is no message of the desired type.
  • ENOPROTOOPT — a given protocol is not available.
  • ENOSPC — there is no space available on the device.
  • ENOSR — there are no stream resources available.
  • ENOSTR — a given resource is not a stream.
  • ENOSYS — a function has not been implemented.
  • ENOTCONN — the socket is not connected.
  • ENOTDIR — the path is not a directory.
  • ENOTEMPTY — the directory is not empty.
  • ENOTSOCK — the given item is not a socket.
  • ENOTSUP — a given operation is not supported.
  • ENOTTY — inappropriate I/O control operation.
  • ENXIO — no such device or address.
  • EOPNOTSUPP — an operation is not supported on the socket. While ENOTSUP and EOPNOTSUPP have the same value on Linux, according to POSIX.1 these error values should be distinct.)
  • EOVERFLOW — a value is too large to be stored in a given data type.
  • EPERM — the operation is not permitted.
  • EPIPE — a pipe is broken.
  • EPROTO — a protocol error.
  • EPROTONOSUPPORT — a protocol is not supported.
  • EPROTOTYPE — wrong type of protocol for a socket.
  • ERANGE — the results are too large.
  • EROFS — the file system is read only.
  • ESPIPE — invalid seek operation.
  • ESRCH — there is no such process.
  • ESTALE — the file handle is stale.
  • ETIME — timer expired
  • ETIMEDOUT — the connection timed out.
  • ETXTBSY — a text file is busy.
  • EWOULDBLOCK — the operation would block.
  • EXDEV — improper link.

Error Constants for Windows Systems

The following are constants for error indicators that are raised in Windows systems.

  • WSAEINTR — an interrupted function call.
  • WSAEBADF — an invalid file handle.
  • WSAEACCES — insufficient permissions to complete the operation.
  • WSAEFAULT — an invalid pointer address.
  • WSAEINVAL — an invalid argument was passed.
  • WSAEMFILE — there are too many open files.
  • WSAEWOULDBLOCK — a resource is temporarily unavailable.
  • WSAEINPROGRESS — an operation is currently in progress.
  • WSAEALREADY — an operation is already in progress.
  • WSAENOTSOCK — the resource is not a socket.
  • WSAEDESTADDRREQ — a destination address is required.
  • WSAEMSGSIZE — the message size is too long.
  • WSAEPROTOTYPE — the wrong protocol type for the socket.
  • WSAENOPROTOOPT — a bad protocol option.
  • WSAEPROTONOSUPPORT — the protocol is not supported.
  • WSAESOCKTNOSUPPORT — the socket type is not supported.
  • WSAEOPNOTSUPP — the operation is not supported.
  • WSAEPFNOSUPPORT — the protocol family is not supported.
  • WSAEAFNOSUPPORT — the address family is not supported.
  • WSAEADDRINUSE — the network address is already in use.
  • WSAEADDRNOTAVAIL — the network address is not available.
  • WSAENETDOWN — the network is down.
  • WSAENETUNREACH — the network is unreachable.
  • WSAENETRESET — the network connection has been reset.
  • WSAECONNABORTED — the connection has been aborted.
  • WSAECONNRESET — the connection has been reset by the peer.
  • WSAENOBUFS — there is no buffer space available.
  • WSAEISCONN — the socket is already connected.
  • WSAENOTCONN — the socket is not connected.
  • WSAESHUTDOWN — data cannot be sent after the socket has been shut down.
  • WSAETOOMANYREFS — there are too many references.
  • WSAETIMEDOUT — the connection has timed out.
  • WSAECONNREFUSED — the connection has been refused.
  • WSAELOOP — a name cannot be translated.
  • WSAENAMETOOLONG — a name was too long.
  • WSAEHOSTDOWN — a network host is down.
  • WSAEHOSTUNREACH — there is no route to a network host.
  • WSAENOTEMPTY — the directory is not empty.
  • WSAEPROCLIM — there are too many processes.
  • WSAEUSERS — the user quota has been exceeded.
  • WSAEDQUOT — the disk quota has been exceeded.
  • WSAESTALE — a stale file handle reference encountered.
  • WSAEREMOTE — the item is remote.
  • WSASYSNOTREADY — the network subsystem is not ready.
  • WSAVERNOTSUPPORTED — the winsock.dll version is out of range.
  • WSANOTINITIALISED — successful WSAStartup has not yet been performed.
  • WSAEDISCON — graceful shutdown is in progress.
  • WSAENOMORE — there are no more results.
  • WSAECANCELLED — an operation has been canceled.
  • WSAEINVALIDPROCTABLE — the procedure call table is invalid.
  • WSAEINVALIDPROVIDER — invalid service provider.
  • WSAEPROVIDERFAILEDINIT — the service provider failed to initialize.
  • WSASYSCALLFAILURE — a system call failure.
  • WSASERVICE_NOT_FOUND — service was not found.
  • WSATYPE_NOT_FOUND — a class type was not found.
  • WSA_E_NO_MORE — there are no more results.
  • WSA_E_CANCELLED — the call was canceled.
  • WSAEREFUSED — a database query was refused.

dlopen Constants

The result of the dlopen command are also included in the os.constants object. The dlopen command is for dynamically loading libraries into memory.

  • RTLD_LAZY — Perform lazy binding. Node.js sets this flag by default.
  • RTLD_NOW — Resolve all undefined symbols in the library before dlopen(3) returns.
  • RTLD_GLOBAL — Symbols defined by the library will be made available for symbol resolution of subsequently loaded libraries.
  • RTLD_LOCAL — Opposite of RTLD_GLOBAL. This is the default behavior if neither RTLD_GLOBAL or RTLD_LOCAL is specified.
  • RTLD_DEEPBIND — Make a self-contained library use its own symbols in preference to symbols from previously loaded libraries.

Priority Constants

The constants below are for setting the priority of scheduled processes. The nice value refers to the integer value for CPU scheduling priority which are used the nice program in Unix and Linux. However, the some of the values are also the same in Windows. The default value is 0. 19 indicates the lowest CPU priority while -20 indicates the highest.

  • PRIORITY_LOW — The lowest process scheduling priority. This corresponds to IDLE_PRIORITY_CLASS on Windows, and a nice value of 19 on all other platforms.
  • PRIORITY_BELOW_NORMAL — This corresponds to BELOW_NORMAL_PRIORITY_CLASS on Windows and a nice value of 10 on all other platforms.
  • PRIORITY_NORMAL — The default process scheduling priority. This corresponds to NORMAL_PRIORITY_CLASS on Windows and a nice value of 0 on all other platforms.
  • PRIORITY_ABOVE_NORMAL — This corresponds to ABOVE_NORMAL_PRIORITY_CLASS on Windows and a nice value of -7 on all other platforms.
  • PRIORITY_HIGH — . This corresponds to HIGH_PRIORITY_CLASS on Windows and a nice value of -14 on all other platforms.
  • PRIORITY_HIGHEST — The highest process scheduling priority. This corresponds to REALTIME_PRIORITY_CLASS on Windows and a nice value of -20 on all other platforms.

The schedule priorities ordered from lowest to highest are — PRIORITY_LOW, PRIORITY_BELOW_NORMAL, PRIORITY_NORMAL, PRIORITY_ABOVE_NORMAL, PRIORITY_HIGH, PRIORITY_HIGHEST .

The Node.js OS module has many useful utility functions for getting information about the computer system that the OS module’s program is running on. The modules have many more properties containing useful information like CPUs, endianness, home directory, IP address, hostname, the platform the program is running on, system uptime, information about the currently logged in user and more.

Categories
JavaScript Nodejs

How To Make a Simple Back End With User Accounts and Authentication

With single-page front-end apps and mobile apps being more popular than ever, the front end is decoupled from the back end. Since almost all web apps need authentication, there needs to be a way for front-end or mobile apps to store user identity data in a secure fashion.

JSON Web Tokens (JWT) is one of the most common ways to store authentication data on front-end apps. With Node.js, there are popular libraries that can generate and verify the JWT by checking for its authenticity. They do this by checking against a secret key stored in the back end and also by checking for an expiry date.

The token is encoded in a standard format that’s understood by most apps. It usually contains user identity data like user ID, user name, etc. It’s given to the user when the user successfully completes authentication.

In this piece, we will build an app that uses JWT to store authentication data.


Overview

For the back end, we’ll use the Express framework, which runs on Node.js, and for the front end, we’ll use the Angular framework. Both have their own JWT add-ons. On the back end, we have the jsonwebtoken package for generating and verify the token.

On the front end, we have the @auth0/angular-jwt module for Angular. In our app, when the user enters user name and password and they are in our database, then a JWT will be generated from our secret key, returned to the user, and stored on the front-end app in local storage. Whenever the user needs to access authenticated routes on the back end, they’ll need the token.

There will be a function in the back-end app called middleware to check for a valid token. A valid token is one that is not expired and verifies as valid against our secret key. There will also be a sign-up and user credential settings pages, in addition to a login page.


Building the App

With this plan, we can begin.

First, we create the front- and back-end app folders. Make one for each.

Then we start writing the back-end app. First, we install some packages and generate our Express skeleton code. We run npx express-generator to generate the code. Then we have to install some packages. We do that by running npm i @babel/register express-jwt sequelize bcrypt sequelize-cli dotenv jsonwebtoken body-parser cors . @babel/register allows us to use the latest JavaScript features.

express-jwt generates the JWT and verifies it against a secret key.bcrypt does the hashing and salting of our passwords. sequelize is our ORM for doing CRUD. cors allows our Angular app to communicate with our back end by allowing cross-domain communication. dotenv allows us to store environment variables in an .env file. body-parser is needed for Express to parse JSON requests.

Then we make our database migrations. First, we run npx sequelize-cli init to generate skeleton code for our database-to-object mapping. Then we run:

npx sequelize-cli model:generate --name User --attributes username:string, password:string, email:string

We make another migration and put:

'use strict';module.exports = {  
  up: (queryInterface, Sequelize) => {  
    return Promise.all([  
      queryInterface.addConstraint(  
        "Users",  
        ["email"],  
        {  
          type: "unique",  
          name: 'emailUnique'  
        }),

      queryInterface.addConstraint(  
        "Users",  
        ["userName"],  
        {  
          type: "unique",  
          name: 'userNameUnique'  
        }),  
  },

  down: (queryInterface, Sequelize) => {  
    return Promise.all([  
      queryInterface.removeConstraint(  
        "Users",  
        'emailUnique'  
      ),

      queryInterface.removeConstraint(  
        "Users",  
        'userNameUnique'  
      ),  
    ])  
  }  
};

This makes sure we don’t have two entries with the same username or email.

This creates the User model and will create the Users table once we run npx sequelize-cli db:migrate .

Then we write some code. First, we put the following in app.js :

require("[@babel/register](http://twitter.com/babel/register)");  
require("babel-polyfill");  
require('dotenv').config();  
const express = require('express');  
const bodyParser = require('body-parser');  
const cors = require('cors');  
const user = require('./controllers/userController');  
const app = express();app.use(cors())  
app.use(bodyParser.urlencoded({ extended: true }));  
app.use(bodyParser.json());

app.use((req, res, next) => {  
  res.locals.session = req.session;  
  next();  
});

app.use('/user', user);app.get('*', (req, res) => {  
  res.redirect('/home');  
});

app.listen((process.env.PORT || 8080), () => {  
  console.log('App running on port 8080!');  
});

We need:

require("@babel/register");  
require("babel-polyfill");

to use the latest features in JavaScript.

And we need:

require('dotenv').config();

to read our config in an .env file.

This is the entry point. We will create userController in the controllers folder shortly.

app.use(‘/user’, user); routes any URL beginning with user to the userController file.

Next, we add the userController.js file:

const express = require('express');  
const bcrypt = require('bcrypt');  
const router = express.Router();  
const models = require('../models');  
const jwt = require('jsonwebtoken');  
import { saltRounds } from '../exports';  
import { authCheck } from '../middlewares/authCheck';

router.post('/login', async (req, res) => {  
    const secret = process.env.JWT_SECRET;  
    const userName = req.body.userName;  
    const password = req.body.password;  
    if (!userName || !password) {  
        return res.send({  
            error: 'User name and password required'  
        })  
    }  
    const users = await models.User.findAll({  
        where: {  
            userName  
        }  
    }) 

    const user = users[0];  
    if (!user) {  
        res.status(401);  
        return res.send({  
            error: 'Invalid username or password'  
        });  
    } 

    try {  
        const compareRes = await bcrypt.compare(password, user.hashedPassword);  
        if (compareRes) {  
            const token = jwt.sign(  
                {  
                    data: {  
                        userName,  
                        userId: user.id  
                    }  
                },  
                secret,  
                { expiresIn: 60 * 60 }  
            );  
            return res.send({ token });  
        }  
        else {  
            res.status(401);  
            return res.send({  
                error: 'Invalid username or password'  
            });  
        }  
    }  
    catch (ex) {  
        logger.error(ex);  
        res.status(401);  
        return res.send({  
            error: 'Invalid username or password'  
        });  
    }});

router.post('/signup', async (req, res) => {  
    const userName = req.body.userName;  
    const email = req.body.email;  
    const password = req.body.password;  
    try {  
        const hashedPassword = await bcrypt.hash(password, saltRounds)  
        await models.User.create({  
            userName,  
            email,  
            hashedPassword  
        })  
        return res.send({ message: 'User created' });  
    }  
    catch (ex) {  
        logger.error(ex);  
        res.status(400);  
        return res.send({ error: ex });  
    }  
});

router.put('/updateUser', authCheck, async (req, res) => {  
    const userName = req.body.userName;  
    const email = req.body.email;  
    const token = req.headers.authorization;  
    const decoded = jwt.verify(token, process.env.JWT_SECRET);  
    const userId = decoded.data.userId;  
    try {  
        await models.User.update({  
            userName,  
            email  
        }, {  
                where: {  
                    id: userId  
                }  
            })  
        return res.send({ message: 'User created' });  
    }  
    catch (ex) {  
        logger.error(ex);  
        res.status(400);  
        return res.send({ error: ex });  
    }});

router.put('/updatePassword', authCheck, async (req, res) => {  
    const token = req.headers.authorization;  
    const password = req.body.password;  
    const decoded = jwt.verify(token, process.env.JWT_SECRET);  
    const userId = decoded.data.userId;  
    try {  
        const hashedPassword = await bcrypt.hash(password, saltRounds)  
        await models.User.update({  
            hashedPassword  
        }, {  
                where: {  
                    id: userId  
                }  
            })  
        return res.send({ message: 'User created' });  
    }  
    catch (ex) {  
        logger.error(ex);  
        res.status(400);  
        return res.send({ error: ex });  
    }});module.exports = router;

The login route searches for the User entry. If it’s found, it then checks for the hashed password with the compare function of bcrypt. If both are successful, then a JWT is generated. The signup route gets the JSON payload of username and password and saves it.

Note that there is hashing and salting on the password before saving. Passwords should not be stored as plain text.

This first is the plain text password, and the second is a number of salt rounds.

updatePassword route is an authenticated route. It checks for the token, and if it’s valid, it will continue to save the user’s password by searching for the User with the user ID from the decoded token.

We will add the authCheck middleware next. We create a middlewares folder and create authCheck.js inside it.

const jwt = require('jsonwebtoken');  
const secret = process.env.JWT_SECRET;export const authCheck = (req, res, next) => {  
    if (req.headers.authorization) {  
        const token = req.headers.authorization;  
        jwt.verify(token, secret, (err, decoded) => {  
            if (err) {  
                res.send(401);  
            }  
            else {  
                next();  
            }  
        });  
    }  
    else {  
        res.send(401);  
    }  
}

You should use the same process.env.JWT_SECRET for generating and verifying the token. Otherwise, verification will fail. The secret shouldn’t be shared anywhere and shouldn’t be checked in to version control.

This allows us to check for authentication in authenticated routes without repeating code. We place it in between the URL and our main route code in each authenticated route by importing and referencing it.

We make an .env file of the root of the back-end app folder, with the following content. (This shouldn’t be checked in to version control.)

DB_HOST='localhost'  
DB_NAME='login-app'  
DB_USERNAME='db-username'  
DB_PASSWORD='db-password'  
JWT_SECRET='secret'

The back-end app is now complete. Now can we can use a front-end app, mobile app, or any HTTP client to sign in.

Categories
JavaScript Rxjs

Rxjs Operators — More Join Operators

Rxjs is a library for doing reactive programming. Creation operators are useful for generating data from various data sources to be subscribed to by Observers.

In this article, we’ll look at some join operators, including exhaust , mergeAll , startsWith and withLatestFrom .

exhaust

The exhaust operator converts higher-order Observables into first-order Observables by dropping inner Observables while previous inner Observable hasn’t completed.

It takes no parameters and returns an Observable that takes the source Observables and propagates values from the first Observable exclusively until it completes before subscribing to the next one.

For example, we can use it as follows:

import { of, interval } from "rxjs";  
import { map, exhaust, take } from "rxjs/operators";

const of$ = of(1, 2, 3);  
const higherOrderObservable = of$.pipe(map(val => interval(500).pipe(take(3))));  
const result = higherOrderObservable.pipe(exhaust());  
result.subscribe(x => console.log(x));

The code above maps the values from the of$ Observable into interval(500).pipe(take(3)) Observables, which emit numbers up to 2 every half a second.

Then we pipe the interval(500).pipe(take(3)) Observables to the exhaust operator. Then all Observables other than the first interval(500).pipe(take(3)) are dropped since it has finished emitting while the next ones are to be executed.

Then we get:

0  
1  
2

outputted from console.log .

mergeAll

mergeAll converts higher-order Observables to first-order Observables which concurrently delivers all values emitted by inner Observables.

It takes the optionalconcurrent argument, which defaults to Number.INFINITY for the maximum number of inner Observables being subscribed to concurrently.

mergeAll subscribes to all inner Observables within higher-order Observables and delivers all the values from them on the output Observable. The returned output Observable only completes when all inner Observables are completed.

Any error emitted by inner Observables will immediately result in errors emitted by the returned Observable.

For instance, we can use it as follows:

import { of } from "rxjs";  
import { map, mergeAll } from "rxjs/operators";

const of$ = of(1, 2, 3);  
const higherOrderObservable = of$.pipe(map(val => of("a", "b", "c")));  
const result = higherOrderObservable.pipe(mergeAll());  
result.subscribe(x => console.log(x));

The code above maps each emitted values from the of$ Observable to of(“a”, “b”, “c”) Observables.

Then the mergeAll operator subscribes to all the of(“a”, “b”, “c”) Observables and then subscribe to each of them and then emit the values of each.

Then we get:

a  
b  
c  
a  
b  
c  
a  
b  
c

from console.log .

We can also change the concurrency by passing in a number to the mergeAll operator.

For example, we can write:

import { of, interval } from "rxjs";  
import { map, mergeAll, take } from "rxjs/operators";

const of$ = of(1, 2, 3);  
const higherOrderObservable = of$.pipe(  
  map(val => interval(1000).pipe(take(2)))  
);  
const result = higherOrderObservable.pipe(mergeAll(1));  
result.subscribe(x => console.log(x));

to make mergeAll subscribe to each child Observable returned from the map operator’s callback sequentially, which will get us:

0  
1  
0  
1  
0  
1

from the console.log .

Or we can change 1 to 5 as follows:

import { of, interval } from "rxjs";  
import { map, mergeAll, take } from "rxjs/operators";

const of$ = of(1, 2, 3);  
const higherOrderObservable = of$.pipe(  
  map(val => interval(1000).pipe(take(2)))  
);  
const result = higherOrderObservable.pipe(mergeAll(5));  
result.subscribe(x => console.log(x));

Then we get:

(3) 0  
(3) 1

outputted from console.log as they’re subscribed to concurrently.

startWith

startsWith returns an Observable that emits the items we want to emit before it begins to emit items from the source Observable.

It takes one argument, which is an array of items that we want to be emitted before the values from the source Observable by the returned Observable.

For example, we can use it as follows:

import { of } from "rxjs";  
import { startWith } from "rxjs/operators";

of(1)  
  .pipe(startWith("foo", "bar"))  
  .subscribe(x => console.log(x));

Then we get:

foo  
bar  
1

as the console.log output.

withLatestFrom

The withLatestFrom operator combines the source Observable with other Observables to create an Observable which emits values that are calculated from the latest values of each, only when the source emits.

It takes a list of arguments, which is an Observable to combine the values with.

For example, we can use it as follows:

import { fromEvent, interval } from "rxjs";  
import { withLatestFrom } from "rxjs/operators";

const clicks = fromEvent(window, "click");  
const timer = interval(1000);  
const result = clicks.pipe(withLatestFrom(timer));  
result.subscribe(x => console.log(x));

We track the clicks of the browser tab with the fromEvent operator. Then we combine the results emitted from the timer Observable with it by using the withLatestFrom operator.

In the end, the result Observable will emit arrays that have the MouseEvent object from the clicks Observable as the first value and the number from the timer Observable as the second value.

The exhaust operator converts higher-order Observables into first-order Observables by dropping inner Observables while previous inner Observable hasn’t completed.

mergeAll converts higher-order Observables to first-order Observables which concurrently delivers all values emitted by inner Observables.

startsWith returns an Observable that emits the items we want to emit before the source Observable begins emitting values.

The withLatestFrom operator combines the source Observable with another Observable and returns an Observable that emits the latest values from both.