Instantiate node module differently per (web) user - node.js

I was wondering what the best practice is for the following scenario:
I am planning to use an npm module for a web servie, where the user enters a access and secret key. Then a module is used which is instantiated like this:
var module = require('module')('ACCESS_KEY','SECRET_KEY');
Each user of course has a different access and secret key. The module exposes several functions which I want to use with the user's access and secret key on his behalf.
Now my question is, how I can 'require' that module with the keys from the database for each user, not just for the whole application with a single static pair. I am on node 8 and using ES6.

The crucial detail here is that this:
var module = require('module')('ACCESS_KEY','SECRET_KEY');
...is equivalent to this:
var moduleFunc = require('module');
var module = moduleFunc('ACCESS_KEY', 'SECRET_KEY');
In other words, 'module' exports a function, and you're calling that function with two arguments ('ACCESS_KEY', 'SECRET_KEY') and assigning the result to module.
That means you can instead require('module') at the top of your file and then use the function it gives you as many times as you want later on, with different arguments.
For example:
const someApi = require('some-api');
// ...later...
app.get('/', (req, res) => {
const { ACCESS_KEY, SECRET_KEY } = getUserKeys(req);
const apiClient = someApi(ACCESS_KEY, SECRET_KEY);
// ...
});

Related

confused about node-localstorage

so I'm making a site with node js, and I need to use localstorage, so I'm using the node-localstorage library. So basically, in one file I add data to it, and in another file I want to retrieve it. I'm not 100% sure about how to retrieve it. I know I need to use localStorage.getItem to retrieve it, but do I need to include localStorage = new LocalStorage('./scratch');? So I was wondering what the localStorage = new LocalStorage('./scratch'); did. So here is my code for adding data:
const ls = require('node-localstorage');
const express = require("express");
const router = express.Router();
router.route("/").post((req, res, next) => {
var localStorage = new ls.LocalStorage('./scratch');
if(req.body.name != undefined){
localStorage.setItem("user", req.body.name);
res.redirect('/')
}
else{
console.log("undefind")
}
});
module.exports = router;
If my question is confusing, I just want to know what var localStorage = new ls.LocalStorage('./scratch'); does.
A drop-in substitute for the browser native localStorage API that runs on node.js.
It creates an instance of the "localStorage" class, which this library provides. The constructor expects the location of the file, the scripts stores the key, value elements in.
Opinion: This looks pointless to me - I guess it fits your use case.

How to use i18next in serverless node js?

I am using Node JS Azure functions. I am trying to internationalize the error messages returned by the functions with i18next. I could find examples with express or plain node server. In these cases middleware pattern can be used.
But for functions, I need a way to call i18next.t('key') with probably a language parameter which I am not able to find. Calling i18next.changeLanguage() before every call to i18next.t('key') doesn't seem practical.
My skeleton code is as follows
const i18next = require("i18next");
const backend = require("i18next-node-fs-backend");
const options = {
// path where resources get loaded from
loadPath: '../locales/{{lng}}/{{ns}}.json',
// path to post missing resources
addPath: '../locales/{{lng}}/{{ns}}.missing.json',
// jsonIndent to use when storing json files
jsonIndent: 4
};
i18next.use(backend).init(options);
exports.getString = (key, lang) => {
//i18next.changeLanguage(lang,
return i18next.t(key);
}
It is possible to fetch translations without doing changeLanguage each time?
As pointed out in the comments you need to call the i18next.changeLanguage(lang) function whenever the language needs to be defined or changed.
You can take a look to the documentation here.
The code could look like this
const i18next = require('i18next')
const backend = require('i18next-node-fs-backend')
const options = {
// path where resources get loaded from
loadPath: '../locales/{{lng}}/{{ns}}.json',
// path to post missing resources
addPath: '../locales/{{lng}}/{{ns}}.missing.json',
// jsonIndent to use when storing json files
jsonIndent: 4
}
i18next.use(backend).init(options)
exports.getString = (key, lang) => {
return i18next
.changeLanguage(lang)
.then((t) => {
t(key) // -> same as i18next.t
})
}

Application-scope Variables in Node.js?

Is there a variable scope in Node.js that persists longer than the request, that is available to all application users? I'd like to create a variable that can be read/written to by multiple app users, like so:
var appScope.appHitCount += 1;
The session scope won't work because it is user specific. Looking for application specific. I couldn't find anything in the Node.js docs. Thanks.
If you have a variable scoped to the app module it will be available and shared by everything within the scope. I imagine in a big app you would need to be careful with this, but it's just regular javascript scoping. For example this will continue to append to the array as you hit it:
const express = require('express')
const app = express()
var input = []
app.get('/:input/', (req, res) => {
var params = req.params
input.push(params.input)
res.send("last input was: " + JSON.stringify(input))
})
app.listen(8080, () => console.log('Example app listening on port 8080!'))
Now visiting 'http://localhost:8080/hi' returns:
last input was: ["hi"]
and then 'http://localhost:8080/there' returns:
last input was: ["hi", "there"]
...etc.
If you want something shared by the entire app (i.e. all the modules) you could set up a module that is require()d by all the modules and i=has the responsibility of getting and setting that value.

node js - are modules shared between users?

Given the following module:
module.exports = function() {
var env;
var module = {};
module.setEnv= function(myEnv) {
env = myEnv; // env may be set to a different value per user
}
module.doActionWithEnv = function() {
...
}
...
return module;
}
I require the module like so:
var myModule = require('/myModule')();
Now my question is, is my module shared between 2 different users that visit the site? By that I mean, can collisions occur if one user sets the private env variable, and then the other calls some function inside the module that depends on env and thus gets the wrong result?
Thanks.
Variables on your server are generally once per server process, not once per user making a request. Some variables like the req and res objects passed to a request handler are uniquely created for each request. Per user variables will typically need some sort of session management layer to allow the server to identify which user is making the request and to then access data stored for that specific user. You can read Express Sessions or Node.js and Express Sessions or Express.js Sessions – A Detailed Tutorial for more info about using sessions in Express and there are a number of NPM modules for implementing sessions with Express though express-session is likely the most popular.
To explain about your code, in this line of your code:
var myModule = require('/myModule')();
You will get a new myModule for every call to that. So, each time you call that module constructor, you get a new myModule object that has a new env inside of it.
But, if you just call that constructor once and have only one myModule variable in your code and multiple requests from your web server on behalf of different users are all using that same myModule variable, then they will all be sharing the same myModule object and thus the same env variable inside of it.
What makes your situation a bit confusing is that modules in node.js that are created when you do require('/myModule') are cached and shared in node.js. So, there is only one actual myModule.js loaded module as far as the node.js system is concerned. But, each time you call the module constructor, your own code creates a new object (which you also named module which makes things confusing). So, if you call that constructor 5 times such as:
var m = require('/myModule');
var x1 = m();
var x2 = m();
var x3 = m();
var x4 = m();
var x5 = m();
Or even:
var x1 = require('/myModule')();
var x2 = require('/myModule')();
var x3 = require('/myModule')();
var x4 = require('/myModule')();
var x5 = require('/myModule')();
Then, you will have 5 separate objects in the variables x1 through x5 and each will have their own env variables inside.
But, if you just do this once:
var myObj = require('/myModule')();
myObj.setEnv("hello");
And, then multiple request handlers all refer to that myObj object like this:
app.get('/request1', function(req, res) {
myObj.setEnv("goodbye");
}};
app.get('/request2', function(req, res) {
myObj.setEnv("adios");
}};
Then, both of these request handlers will be operating on the same myObj object no matter what user initiates the request.
How can I avoid this problem then?
If you want per-user information stored on your server, then you would typically use sessions. While there are many ways to implement a session, they usually set a unique cookie for each user's browser when they first visit your site. There is then a storage mechanism on the server that can access data that belongs to the user with that cookie value. You don't use normal JS variables for storing each user's state. You would typically use either an object lookup (by cookie ID) or some sort of database.
Since it looks like you are using Express, there are several NPM modules that will hook into Express and implement sessions for you. The most popular session implementation for Express is express-sessions.

Explain to Mean.io beginner how Mean.io sample package's authentication works

I'm learning mean.io from this tutorial video, which shows the example package (created by mean package mymodule. It is also described under "Packages" on the docs). I would like help in understanding how the given authentication/authorization works.
The default sample package/module has a simple user authentication that on the client side
myapp/packages/mymodule/public/views/index.html contains:
<li>
Server route that anyone can access
</li>
<li>
Server route that requires authentication
</li>
<li>
Server route that requires admin user
</li>
On the server side,
myapp/packages/mymodule/server/routes/mymodule.js, contains:
// The Package is past automatically as first parameter
module.exports = function(Mymodule, app, auth, database) {
app.get('/mymodule/example/anyone', function(req, res, next) {
res.send('Anyone can access this');
});
app.get('/mymodule/example/auth', auth.requiresLogin, function(req, res, next) {
res.send('Only authenticated users can access this');
});
app.get('/mymodule/example/admin', auth.requiresAdmin, function(req, res, next) {
res.send('Only users with Admin role can access this');
});
...
};
The magic of the different authentication relies on the second argument of app.get() with additional authentication callback: none, auth.requiresLogin, or auth.requiresAdmin.
This is the authentication magic (also on github):
myapp/packages/access/server/config/authorization.js:
/**
* Generic require login routing middleware
*/
exports.requiresLogin = function(req, res, next) {
if (!req.isAuthenticated()) {
return res.send(401, 'User is not authorized');
}
next();
};
/**
* Generic require Admin routing middleware
* Basic Role checking - future release with full permission system
*/
exports.requiresAdmin = function(req, res, next) {
if (!req.isAuthenticated() || !req.user.hasRole('admin')) {
return res.send(401, 'User is not authorized');
}
next();
};
QUESTION A: Why is it "exports.requiresLogin" and "exports.requiresAdmin" in the authorization.js instead of "somethingelse.requiresLogin" and "somethingelse.requiresAdmin"? Is this "exports" related to the myapp/packages/access/server/config/passport.js's exports: module.exports = function(passport) { ...}, github? If so, in what circumstances can we use this "exports"?
Since authentication's authorization rules is written up in package "access" and used in package "mymodule", Mean.io packages are not independent of each other. The Access package is registered on
myapp/packages/access/app.js, github:
var mean = require('meanio'),
Module = mean.Module,
passport = require('passport');
var Access = new Module('access');
Access.register(function(database) {
// Register auth dependency
var auth = require('./server/config/authorization');
require('./server/config/passport')(passport);
// This is for backwards compatibility
mean.register('auth', function() {
return auth;
});
mean.register('passport', function() {
return passport;
});
Access.passport = passport;
Access.middleware = auth;
return Access;
});
QUESTION B: Does Mean.io automatically link all the packages or is there code to link packages somewhere? Is it linked due to the part with "This is for backwards compatibility" shown below? If so, where can "auth" be used? All the packages myapp/packages/? How about in the mean.io base app directory myapp/?
var auth = require('./server/config/authorization');
// This is for backwards compatibility
mean.register('auth', function() {
return auth;
});
QUESTION C: Why is it "Access.passport = passport;", but "middleware" for "Access.middleware = auth;"? What what happen if it were "Access.auth = auth"?
REGARDING QUESTION A (on the use of exports)
In Node.js, assigning values to the exports object makes those values available to the code that requires the source file.
For example, given file foo.js:
exports.foo = "FOO";
exports.bar = "BAR";
and file main.js:
var foo = require('foo.js');
console.log('foo=',foo.foo,'; bar=',foo.bar);
running node main.js will output foo= FOO ; bar= BAR.
See, for example, Node's module documentation or this write-up on require and exports.
REGARDING QUESTION B (on package "linking")
The answer to this question is the complement to the answer to Question A.
There is code to "link" the packages. It is the require statement.
In your app.js source code, the first line (reading var mean = require('meanio')) will set the local variable mean to whatever values are assigned to exports object is when meanio.js and/or the meanio module is loaded.
Same with passport = require('passport'). In that case, the local variable passport will be equal to the value of exports after index.js in the passport module is loaded.
REGARDING QUESTION C
I'm not entirely sure what you are asking here, but let me take a stab at it.
In this case:
1) var mean = require('meanio') in line 1 "imports" the meanio module, such that the local variable mean is more or less set equal to the value of exports in the meanio module.
2) Module = mean.Module in line 2 sets the local variable Module equal to the value of mean.Module, which must have been assigned in the meanio module.
3) var Access = new Module('access') is instantiating an instance of the Module class, assigning it to the local variable Access.
4) Access.passport = passport assigns the instance variable named passport within the instance of meanio.Module named Access (to the value of the passport module required on line #3)
5) Access.middleware = auth assigns the instance variable named middleward within the instance of meanio.Module named Access (to the value returned by require('./server/config/authorization') in line 11).
I'm not familiar with the "meanio" module, but based on this code it looks like you are configuring the meanio.Module("access") instance (named Access) by assigning specific "magic" variable names.
In other words, rather than Access.passport = passport; Access.middleware = auth you might have Access.setPassport(passport); Access.setMiddleware(auth) or (rather than line 5) var Access = new Module('access',passport,auth).
That is, the author of the "meanio" module seems to have decided to use special variable names to configure the class rather than "setter" methods or parameters passed to the constructor. I assume that somewhere in the meanio code you'll find a reference to something like this.middleware and this.passport, where the code is assuming you have "filled in" those instance variables as happens in the last few lines in your code sample.
If you were to add Access.auth = auth then all that would happen is that the Access object would have a new attributed named auth whose value is equal to the that of the local variable auth.
If you used Access.auth instead of Access.middleware, I assume whatever code in the Access class that is using this.middleware will fail, since no value was ever assigned to Access.middleware and Access.auth is not one of the "magic" variable names that meanio is looking for.

Resources