Authentication with node.js, nano and CouchDB - node.js

Is there a way to change the config parameters in nano after initialization? I'd like to init nano with:
nano = require('nano')('http://127.0.0.1:5984')
and later change user and password, after a user submits the login form. I always get an error:
nano.cfg.user = params.user.name
TypeError: Cannot set property 'user' of undefined
Or should I fork nano and write an auth function to adjust the values?

I can't test it right now, but, looking at the sources, you can note two things:
that configuration is exposed as config, not cfg;
that the config option for connection is url.
Then I think you need to set the url configuration option to a new value with authentication parameters:
nano.config.url = 'http://' + params.user.name + ':' + params.user.password + '#localhost:5984';
Or you can keep a configuration object as in couch.example.js and do something like:
cfg.user = params.user.name;
cfg.pass = params.user.password;
nano.config.url = cfg.url;
UPDATE: here's a complete example:
var cfg = {
host: "localhost",
port: "5984",
ssl: false
};
cfg.credentials = function credentials() {
if (cfg.user && cfg.pass) {
return cfg.user + ":" + cfg.pass + "#";
}
else { return ""; }
};
cfg.url = function () {
return "http" + (cfg.ssl ? "s" : "") + "://" + cfg.credentials() + cfg.host +
":" + cfg.port;
};
var nano = require('nano')(cfg.url()),
db = nano.use('DB_WITH_AUTH'),
docId = 'DOCUMENT_ID';
function setUserPass(user, pass) {
cfg.user = user;
cfg.pass = pass;
nano.config.url = cfg.url();
}
db.get(docId, function (e, r, h) {
if (e) {
if (e['status-code'] === 401) {
console.log("Trying again with authentication...");
setUserPass('USENAME', 'PASSWORD');
db.get(docId, function (e, r, h) {
if (e) {
console.log("Sorry, it did not work:");
return console.error(e);
}
console.log("It worked:");
console.log(r);
console.log(h);
});
return;
}
console.log("Hmmm, something went wrong:");
return console.error(e);
}
console.log("No auth required:");
console.log(r);
console.log(h);
});

The authentication can be send as part of the http header:
if(cfg.user && cfg.pass) {
req.headers['Authorization'] = "Basic " + new Buffer(cfg.user+":"+cfg.pass).toString('base64');
}
The username and password can be set with a 'auth'-function:
function auth_db(user, password, callback) {
cfg.user = user;
cfg.pass = password;
return relax({db: "_session", method: "GET"}, callback);
}

Related

How to migrate SSE chat node express to node hapi

I was testing a SSE node express chat in localhost.It was working perfectly. I was including a chat_server in a demo with hapijs as modular server...and it complain about the express syntax. How can I migrate the code to the right syntax in hapijs?
I am trying to solve changing writeHead and write methods because it's complaing about and adding stream package after searching answers in internet.
/*
* Request handlers
*/
function handleGetChat(req, res) {
console.log('handleGetChat received.');
// res(chatStream).code(200).type('text/event-stream').header('Connection', 'keep-alive').header('Cache-Control','no-cache');
// chatStream.write('\n');
(function(clientId) {
clients[clientId] = res;
clientNames[clientId] = req.params.name;
console.log('name {$req.params.name}');
req.on("close", () => {
delete clients[clientId];
actUserName = "";
sendText(clientNames[clientId] + " disconnected!", false);
delete clientNames[clientId];
});
})(++clientId);
sendText(req.params.name + " connected!", false);
let allMates = "";
for (cliId in clientNames) {
allMates += `${clientNames[cliId]}`;
if (cliId < clientId) allMates += " ";
}
sendText(`logged in [${allMates}]`, false);
}
let sendText = (text, showUserName = true) => {
for (clientId in clients) {
allMates += `${clientNames[cliId]}`;
if (cliId < clientId) allMates += " ";
}
sendText(logged in [${allMates}], false);
}
let sendText = (text, showUserName = true) => {
for (clientId in clients) {
let data = "";
let date = new Date();
let timestamp = `[${date.getHours()}:${date.getMinutes()}]`;
if (showUserName) {
data = `data: ${timestamp} <${actUserName}> ${text}\n\n`;
} else {
data = `data: ${timestamp} ${text}\n\n`;
}
//chatStream.push('data: ' + "\n\n");
}
};
function handleWriteChat(req, res) {
actUserName = req.body.name;
sendText(req.body.text);
res.json({ success: true });
}
The commented lines in the code above are the lines with syntax error in hapi. I was already changing the originals write and writeHead with chatstream.

Unable to Get Row Count Using ibm_db for NodeJS

I have an issue with not able to get the affected rows result from the following
During the debug I notice it always crashes at conn.querySync(query.sqlUpdate, params);
Console.log is not showing anything as well.
What did I do wrong here?
CODE
//imports
const format = require('string-format');
const query = require('../db/query');
const message = require('../common/message');
const constant = require('../common/constant');
var ibmdb = require("ibm_db");
require('dotenv').config();
// access the environment variables for this environment
const database = "DATABASE=" + process.env.DATABASE + ";";
const hostname = "HOSTNAME=" + process.env.HOSTNAME + ";";
const uid = "UID=" + process.env.UID + ";";
const pwd = "PWD=" + process.env.PWD + ";";
const dbport = "PORT=" + process.env.DBPORT + ";";
const protocol = "PROTOCOL=" + process.env.PROTOCOL;
const connString = database+hostname+uid+pwd+dbport+protocol;
function updateContact(params) {
ibmdb.open(connString, function(err, conn){
//blocks until the query is completed and all data has been acquired
var rows = conn.querySync(query.sqlUpdate, params);
console.log(rows);
});
}
module.exports.updateContact = updateContact;
I finally understand what the problem is.
The problem lies in me using the querySync function. This function not return affected row counts.
https://github.com/ibmdb/node-ibm_db/blob/master/APIDocumentation.md#querySyncApi
The proper way is to use prepare followed by executeNonQuery.
https://github.com/ibmdb/node-ibm_db/blob/master/APIDocumentation.md#executeNonQueryApi
So from the API, i modify my codes.
...
conn.prepare(query.SQL_UPDATE, function (error, stmt) {
if (err) {
console.log(err);
return conn.closeSync();
}
stmt.executeNonQuery(params, function (err, result) {
if( err ) {
console.log(err);
}
else {
console.log("Affected rows = " + result);
}
//Close the connection
conn.close();
});
});
...

Express redirect firebase can't set headers after they are sent

I am using nodejs express and firebase for my database. So what I am trying to do is upon user's post request, update firebase data and redirect user to another page. But I keep getting Error: Can't set headers after they are sent.
Here is my code in controller.js file:
app.post('/carpark', urlencodedParser, function(req,res){
req.session.carpark = req.body.carpark;
lotsRef.orderByChild('CarparkName').equalTo(req.session.carpark).on('value', function(snapshot){
for (var key in snapshot.val()) {
if (snapshot.val()[key]['Availability'] == true) {
firebase.database().ref('Lots/'+ key).update({'Availability': false });
res.redirect('checkin');
break;
}
}
});
EDITED:
app.post('/carpark', urlencodedParser, function(req,res){
req.session.carpark = req.body.carpark;
lotsRef.orderByChild('CarparkName').equalTo(req.session.carpark).on('value', function(snapshot){
for (var key in snapshot.val()) {
var allocatedtime = new Date().getHours() + ':' + (new Date().getMinutes() <10 ? '0' : '') + new Date().getMinutes() + ':' + (new Date().getSeconds() <10 ?'0' : '') + new Date().getSeconds();
req.session.key = key;
req.session.LotID = snapshot.val()[key]['LotID'];
req.session.AllocatedTime = allocatedtime;
req.session.SerialNum = snapshot.val()[key]['SerialNumber'];
var date = new Date().getFullYear() + "-" + (new Date().getMonth()+1) + "-" + new Date().getDate();
req.session.DateAllocated = date;
console.log(req.session);
firebase.database().ref('Lots/'+ req.session.key).update({'Availability': false });
break;
}
}
res.redirect('checkin');
});
The redirect should be moved outside For loop:
app.post('/carpark', urlencodedParser, function(req,res){
req.session.carpark = req.body.carpark;
lotsRef.orderByChild('CarparkName').equalTo(req.session.carpark).on('value', function(snapshot){
for (var key in snapshot.val()) {
if (snapshot.val()[key]['Availability'] == true) {
firebase.database().ref('Lots/'+ key).update({'Availability': false });
break;
}
}
res.redirect('checkin');
});
But this will redirect to 'checkin' irrespective of your if clause, so that depends on your scenario whether you want to redirect to some other page when the if clause is not true even once.

Issue with uploading files on azure blob storage

I am working with azure blob storage, i have done that with PHP language, now i want to upload files on azure blob storage with jquery, so i used one plugin for that, when i try to upload file on that it is giving me error in console
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at (Reason: CORS header
‘Access-Control-Allow-Origin’ missing).
I read about the CORS configuration, and i enable that configuration in Azure Blob Storage, here is my screenshot for that
Here is my jquery code
$(function () {
var ju = {
sasUrl: $('#txtSAS'),
list: $('#tbFileList tbody'),
btnUpload: $('#btnUpload'),
btnClear: $('#btnClear'),
btnAddFile: $('#btnAddFile'),
sasSearchName: 'sas',
btnLink: $('#btnLink'),
linkPopover: $('#linkPopover'),
init: function () {
this.root = location.href;
if (this.root.indexOf('?') > 0) {
this.root = this.root.substr(0, this.root.indexOf('?'));
this.root = this.root.replace(/#/g, '');
}
this.btnClear.hide();
var sas = this.queryString(this.sasSearchName);
if (sas) {
this.sasUrl.val(sas);
}
this.list.blobuploader(
{
url: ju.sasUrl.val(),
beforeSend: function (blob) {
},
progress: function (blob) {
ju.progress(blob.element.closest('tr'), blob.loaded, blob.size);
},
success: function (blob, data, status) {
var st = blob.speed(true);
var msg = 'total time: ' + ((st.end - st.start) / 1000).toFixed(2) + 'S<br/>'
+ 'max speed: ' + st.max + '<br/>'
+ 'min speed: ' + st.min + '<br/>'
+ 'average speed: ' + st.average;
ju.status(blob.element, msg);
var download = '<a target="_blank" role="button" class="btn btn-link" href="'
+ blob.blobUrl
+ '" >' + blob.name + '</a>';
ju.log(blob.element.closest('tr').find('td:first'), download);
},
error: function (blob, block, xhr, desc, err) {
var msg = $('<span></span>');
msg.append('upload ' + blob.name + ' error.');
var btn = $('<button type="button" id="btnUpload" class="btn btn-sm btn-primary pull-right" role="button">Retry</button>');
btn.click(function () {
ju.retry($(this).closest('tr'));
});
msg.append(btn)
ju.status(blob.element, msg, 'danger');
}
});
this.btnClear.click(function () {
ju.clear();
});
this.btnAddFile.find('input').on('change', function () {
ju.add();
});
this.btnUpload.click(function () {
ju.upload();
});
this.btnLink.popover({
html: true,
content: this.linkPopover,
container: 'body'
});
this.btnLink.on('shown.bs.popover', function () {
var panel = $('#linkPopover');
panel.find('#txtShareUrl').val(ju.getLongUrl());
panel.find('#ckShortUrl').click(function () {
if ($(this).is(':checked')) {
ju.generateShortUrl();
} else {
panel.find('#txtShareUrl').val(ju.getLongUrl());
}
})
panel.find('.close').click(function () {
ju.btnLink.popover('toggle');
});
panel.find('#ckShortUrl').attr('checked', false);
panel.find('.loading').hide();
});
this.sasUrl.on('change', function () {
ju.linkPopover.find('#ckShortUrl').attr('ckecked', false);
ju.linkPopover.find('.loading').hide();
});
var code = $('.prettyprint');
code.text(code.text().replace('site-domain', location.origin));
},
progress: function (tr, loaded, total) {
var percent = (loaded / total * 100).toFixed(2);
var span = tr.find('td:last .percent');
if (span.length == 0) {
span = $('<span class="percent"/>').appendTo(tr.find('td:last').empty());
}
span.text(percent + '%');
},
log: function (td, message, type) {
var div = td.empty();
if (type) {
div = $('<div class="alert alert-' + type + '"/>').appendTo(td);
}
if (message instanceof jQuery) {
div.append(message);
} else {
div.html(message);
}
},
information: function (element, info, type) {
var td = element.closest('tr').find('td:eq(1)');
if (info) {
ju.log(td, info, type);
} else {
return td.html();
}
},
status: function (element, message, type) {
var td = element.closest('tr').find('td:last');
if (message) {
ju.log(td, message, type);
} else {
return td.html();
}
},
add: function () {
var tr = $('<tr/>'), td = $('<td/>');
var file = this.btnAddFile.find('input');
this.btnAddFile.append(file.clone(true));
var f = file.get(0).files[0];
td.append(file)
.append(f.name)
.appendTo(tr);
td = $('<td/>')
.append(f.type, f.type ? '<br/>' : '', (f.size / 1000).toFixed(2) + 'KB')
.appendTo(tr);
$('<td><span class="percent"></span></td>').appendTo(tr);
tr.appendTo(this.list);
this.btnClear.show();
},
setProperties: function () {
if (!this.sasUrl.val()) {
alert('Please typedin the Container SAS');
return;
}
var blockSize = parseInt($('#txtBlockSize').val());
var maxThread = parseInt($('#txtMaxThread').val());
if (isNaN(blockSize) || isNaN(maxThread)) {
alert("Block Size and Max Thread can only be number.");
return;
}
if (blockSize > 4096) {
alert('The block size should be less than 4096kb');
return;
}
if (blockSize < 1) {
alert('The block size should be greater than 1kb');
return;
}
if (maxThread < 0) {
maxThread = 0;
}
this.list.blobuploader('option', { maxThread: maxThread, blockSizeKB: blockSize, url: this.sasUrl.val() });
return true;
},
upload: function () {
if (this.setProperties()) {
this.list.blobuploader('upload');
}
},
retry: function (tr) {
if (this.setProperties()) {
if (tr) {
var element = tr.find('input[type="file"]');
var blob = this.list.blobuploader('blob', element);
this.list.blobuploader('retry', blob);
} else {
this.list.blobuploader('retry');
}
}
},
clear: function () {
this.list.empty();
this.btnClear.hide();
},
queryString: function (name, value) {
if (!value) {
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results == null ? "" : atob(decodeURIComponent(results[1].replace(/\+/g, " ")));
} else {
return name + '=' + encodeURIComponent(btoa(value));
}
},
getLongUrl: function () {
return this.root + '?' + this.queryString('sas', this.sasUrl.val());
},
generateShortUrl: function () {
var request = gapi.client.urlshortener.url.insert({
'resource': {
'longUrl': this.getLongUrl()
}
});
request.execute(function (response) {
if (response.id != null) {
ju.linkPopover.find('.loading').hide();
ju.linkPopover.find('#txtShareUrl').val(response.id);
}
else {
ju.linkPopover.find('.loading').text('error.');
}
});
}
}
ju.init();
prettyPrint();
})
function gapiload() {
gapi.client.setApiKey('AIzaSyDzeVB4WDi6azVvIu6uc8hIhWxf99dB6c8');
gapi.client.load('urlshortener', 'v1', function () { });
}
In the input we need to add "Input Your Container SAS Here" i am adding there
https://*****.blob.core.windows.net/?sv=2017-04-17&ss=bfqt&s‌​rt=sco&sp=rwdlacup&s‌​e=2017-09-10T01:51:2‌​0Z&st=2017-09-09T17:‌​51:20Z&spr=https&sig‌​=****** this SAS url, it will get this SAS url and after then we need to select file and upload it.
Can anyone please tell me what is exact issue ?
Thanks
I also download and test the library, it worked fine with following setting on my blob storage service. The MaxAgeInSeconds setting will cache the preflight OPTIONS request. I suggest you reset it to 0 and run your code again(Please use different browsers to test it).
In addition, there are multi CORS setting under Azure Storage panel. Please mark sure that you were setting the right one for Azure Blob Storage.

Accessing Cloudant using nodejs nano

Is there a gist which I can follow to use to connect to cloudant using nano / nodejs. Or, is there any other library which I can use to connect from nodejs to cloudant. Here is the error I encounter, when i try to connect.
description: 'one of _writer, _creator is required for this request',
Here is how my code looks
// require nano, point it at cloudant's root
var config = require('config');
var nano = require('nano')({url: config.cloudant.url})
, username = config.cloudant.username
, userpass = config.cloudant.password
, cookies = {}
, callback = console.log // this would normally be some callback
;
nano.auth(username, userpass, function (err, body, headers) {
if (err) {
return callback(err);
}
if (headers && headers['set-cookie']) {
cookies['user'] = headers['set-cookie'];
}
callback(null, "it worked");
});
var db = require('nano')({
'url': config.cloudant.url + '/' + config.cloudant.database,
'cookie': cookies['user']
});
After this, when i try to connect - i get the error
var db = require('nano')({
'url': config.cloudant.url + '/' + config.cloudant.database,
'cookie': cookies['user']
});
var doc = {"hello": "world"};
db.insert(doc, function (err, body, headers) {
if (err) {
return callback(err);
}
// change the cookie if couchdb tells us to
if (headers && headers['set-cookie']) {
cookies['user'] = headers['set-cookie'];
}
callback(null, "it worked");
});
You can try using this https://github.com/cloudant/nodejs-cloudant . It is a wrapper over nano to directly connect with cloudant.

Resources