unexpected `server_admin required` error with Cloudant NodeJS - node.js

I am using the Cloudant service via the Node.JS module, with the credentials provided via Bluemix VCAP_SERVICES (or a local copy). The instance is created with
var Cloudant = require('cloudant');
// var cloudantCreds obtained from process.env.VCAP_SERVICES
var username = cloudantCreds.username;
var password = cloudantCreds.password;
var cloudant = Cloudant({
account:username,
password:password
});
I had written a function that would automatically create/delete a database when a user requested, and it successfully worked. This internally used
cloudant.db.create(databaseName, function(err, res){
// Handle
});
However, recently I get an error:
'server_admin access is required for this request'
I am only using one set of credentials and one account. Using these credentials in the command line with curl allows me to successfully create/delete databases, but it seems to be unable to do this via the node.js module?
As far as I can remember, I haven't changed any code related to this function of my Node.js server.
What is causing me to now require server_admin access? From the nature of the error message, I am presumably authenticated, but not authorised?

It turns out it was an error on my behalf, although Cloudant was not particularly informative.
I was trying to create databases with disallowed names, such as beginning with an underscore or containing a capital letter. Change the database name, and it all works correctly.

if your database is prefixed with underscore it will throw errors...

Related

firebase.auth().currentUser is returning null when i re-execute a script in node.js cli

I m creating a node cli and i m using firebase auth in it
everything is working fine
there is a command to login and when the user executes it asks for credentials. after the submission i get a custom auth token from an api and then i use signinwithcustomtoken and i get value of 'currentUser' as expected.
According to this page Access Firebase in your app i can use firebase client sdk in a node.js app for auth
Problem
but as when i execute another command to show profile data and in that when i try to access firebase.auth().currentUser it returns null :(
I m not creating any kind of server.
I think firebase is recreating a new instance every time i run a command
but why doesn't firebase loose instance in angular ?
In Node.js deployments, the default Auth state persistence mode is firebase.auth.Auth.Persistence.NONE for security reasons as mentioned at the bottom of the Modifying the ASP section. This means that the user state is cleared whenever you close your script.
Prior to logging in with your authentication token, you will need to use the following code to change the mode to match a browser:
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL) // <-- this bit
.then(function() {
// Users will now be logged in until they explicitly log out
return firebase.auth().signInWithCustomToken(token);
})
.catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
});

Should I worry to close db connection while connecting cloudant db from nodejs using cloudant module?

I am connecting to cloudant using "cloudant" module in nodejs (npm install --save cloudant). Below is the code to initiate the db connection variable and then to use it.
//instantiate a cloudant var with the cloudant url. The url has id, password in it.
cloudant = require('cloudant')(dbCredentials.url);
//set the middleware with the db name
db = cloudant.use(dbCredentials.dbName);
//use the db variable to insert data into the db
function(req){
db.insert({
name:req.name,
age:req.age
},id,function(err,doc){
....
});
};
Should I be worrying about closing the connection after I use db variable? It does not make sense to me since we are not using any connection pool here. To me we are simply instantiating the db variable with the endpoint, credentials and db name. Later we are calling the cloudant resources as ReST APIs. I am slightly confused here and dont think we need to do any close connection (which in fact means nothing but nullifying the cloudant variable). Can please share any comments, whether I am wrong or right? Thanks in advance.
By default, the Cloudant library uses the default Node.js connection pooling so it will respect the server's "Keep-Alive" instruction, but is nothing that you need to worry about. Simply keep making Cloudant library function calls and the library will make HTTP connections when required - reusing existing connections when necessary, creating new ones in other cases.

nodejs' req.hostname as mongo doc index. bad practice?

I'm building a nodejs app I would like to make available under various settings by my customers. I want my customers to build their websites on top of my app, so: - the app can be configured in a way that domains "A.com" and "B.com" use the configuration "X" of the app, while "C.com" uses "Y", etc. - I'm thinking about using kubernetes and dockers containers to isolate version "X", "Y" etc. of my app - I'm also thinking about using nginx for reverse-proxy
Each domain will have its distinct documents in a mongodb collection. Because I need a way to retrieve the right data, I'm giving each domain a unique token matching their documents. All the tokens are also saved in mongodb and will be retrieved on my (nodejs) server's start or updated on the fly. The tokens will be saved on a "app.locals" variable: - I'm thinking about having a middleware that will grap the domain from every request (req.hostname) and get the corresponding token
// set locals
app.locals.domainTokens = {};
after retrieving and assigning the tokens, "domainTokens" will look like:
app.locals.domainToken = {
"Acom" : "token_1",
"Bcom" " "token_2" // and so on
}
// the middleware
function grabToken(req, res, next) {
var tokens = app.locals.domainToken,
host = req.hostname;
req.params.token = host ? tokens[host] : undefined;
next();
}
When new customers register, tokens will be assigned on the fly for their domain (containers talk to each other, right?).
So basically, when a request is made for "A.com", my middleware sets the "token" so that the mongodb documents related to "A.com" can be found and sent back to client running version "X" of my app (nginx).
What do you think about this approach ? is it unsafe? a bad practice? do you have a better suggestion to implement it? Am I better off using one container per domain ? (I would have to monitor hundreds of nodejs instances instead of 3 or 4)
Also, is it possible to dynamically configure a Nginx server?

Should I use a server method or Collection.insert() to insert a record using Meteor?

I'm trying to decide between two methods for inserting a new document to a collection from the client using Meteor.js. Call a Server Method or using the db API directly.
So, I can either access the db api directly on the client:
MyCollection.insert(doc)
Or, I can create a new Server Method (under the /server dir):
Meteor.methods({
createNew: function(doc) {
check(doc, etc)
var id = MyCollection.insert(doc);
return project_id;
}
});
And then call it from the client like this:
Meteor.call('createNew', doc, function(error, result){
// Carry on
});
Both work but as far as I can see from testing, I only benefit from latency compensation (the local cache updating and showing on the screen before the server responds) if I hit the db api directly, not if I use a Server Method, so my preference is for doing things this way. But I also get the impression the most secure approach is to use a Method on the server (mainly because Emily Stark gave it as an example in her video here) but then the db api is available on the client no matter what so why would a Server Method be better?
I've seen both approaches taken when reading source code elsewhere so I'm stumped.
Note. In both cases I have suitable Allow/Deny rules in place:
MyCollection.allow({
insert: function(userId, project){
return isAllowedTo.createDoc(userId, doc);
},
update: function(userId, doc){
return isAllowedTo.editDoc(userId, doc);
},
remove: function(userId, doc){
return isAllowedTo.removeDoc(userId, doc);
}
});
In short: Which is recommended and why?
The problem was that I had the method declarations under the /server folder, so they were not available to the client and this broke latency compensation (where the client creates stubs of these methods to simulate the action but in my case could not because it couldn't see them). After moving them out of this folder I am able to use Server Methods in a clean, safe and latency-compensated manner (even with all my Allow/Deny rules set to false - they do nothing and only apply to direct db api access from the client, not server).
In short: don't use the db api on the client or allow/deny rules on the server, forget they ever existed and just write Server Methods, make sure they're accessible to both client and server, and use these for crud instead.

Using NodeJs with Firebase - Security

Due to the need to do some server side code - mainly sending emails I have decided to use Nodejs & Express for the server side element along with Firebase to hold the data - Partly from a learning experience.
My question is whats the best approach with regards to using the client side Firebase library and the Nodejs library when doing authentication using the Simple Email & Password API. If I do the authentication client side and then subsequently call a different route on the NodeJS side will the authentication for that user be carried across in the request. What would be the approach to test the user is authenticated within Node.
One approach I assume is to get the current users username & password from firebase and then post these to NodeJS and then use the firebase security API on the server to test.
Essentially the problem here is you need to securely convey to your NodeJS server who the client is authenticated as to Firebase. There are several ways you could go about this, but the easiest is probably to have all of your client<->NodeJS communication go through Firebase itself.
So instead of having the client hit a REST endpoint served by your NodeJS server, have the client write to a Firebase location that your NodeJS server is monitoring. Then you can use Firebase Security Rules to validate the data written by the client and your server can trust it.
For example, if you wanted to make it so users could send arbitrary emails through your app (with your NodeJS server taking care of actually sending the emails), you could have a /emails_to_send location with rules something like this:
{
"rules": {
"emails_to_send": {
"$id": {
".write": "!data.exists() && newData.child('from').val() == auth.email",
".validate": "newData.hasChildren(['from', 'to', 'subject', 'body'])"
}
}
}
}
Then in the client you can do:
ref.child('emails_to_send').push({
from: 'my_email#foo.com',
to: 'joe#example.com',
subject: 'hi',
body: 'Hey, how\'s it going?'
});
And in your NodeJS code you could call .auth() with your Firebase Secret (so you can read and write everything) and then do:
ref.child('emails_to_send').on('child_added', function(emailSnap) {
var email = emailSnap.val();
sendEmailHelper(email.from, email.to, email.subject, email.body);
// Remove it now that we've processed it.
emailSnap.ref().remove();
});
This is going to be the easiest as well as the most correct solution. For example, if the user logs out via Firebase, they'll no longer be able to write to Firebase so they'll no longer be able to make your NodeJS server send emails, which is most likely the behavior you'd want. It also means if your server is temporarily down, when you start it back up, it'll "catch up" sending emails and everything will continue to work.
The above seems like a roundabout way of doing things, I would use something like https://www.npmjs.com/package/connect-session-firebase and keep firebase as the model, handling all routes through express. Easier if your express server is rendering templates and not just behaving as a JSON API.
If you are using Firebase Authentication, the client side can import the Firebase Library (e.g. for javascript) and authenticate directly with the library itself
import firebase from 'firebase/app';
const result = await firebase.auth().signInWithEmailAndPassword(_email, _password);
After that, the client can to obtain the ID Token, this token will be informed on each request that will be made to the server (e.g. as header).
const sendingIdToken = await firebase.auth().currentUser.getIdToken();
On the Node.js server side, you can install the Firebase Admin SDK, to verify if the user is authenticated on the Node.js server, like:
// Let's suppose the client informed the token as header
const receivingIdToken = req.headers['auth-token'];
admin.auth().verifyIdToken(receivingIdToken, true)
.then((decodedIdToken) => { /* proceed to send emails, etc */}, (error) => {...});
The Firebase Admin SDK gives full permissions to the Database, so keep the credentials safe.
You should also configure the Security Rules on Firestore (or Firebase Realtime), so the client side can still perform specific operations directly to the database (e.g. listening for realtime changes on a collection), but you can also restrict all access if you want the client to only interact with the node.js server.
For more details, I developed an example of a node.js server that uses the Firestore Database and handles security and more.

Resources