PouchDB / CouchDB / Cloudant PUT _security - couchdb

PouchDB and Cloud-Cloudant setup.
Development environment: Ionic hybrid App (AngularJS).
Would like to create database and set up permission from code.
Tried
put _security but received error code 400. Only reserved document ids may start with underscore.
Refer to Cloudant API regarding modifying permission. But failed to implement. Anyone could eliminate about how to perform this?
https://docs.cloudant.com/authorization.html#modifying-permissions
Example of my code.
var attendanceSecurity = {
"_id": "_security",
"cloudant": {
"nobody": []
}
};
attendanceSecurity['cloudant'][user.id] = ["_reader","_writer","_replicator"];
var user2 = {
name: username,
password: password
};
var pouchOpts = {
skipSetup: false
};
var ajaxOpts = {
ajax: {
headers: {
Authorization: 'Basic ' + window.btoa(user2.name + ':' + user2.password)
}
}
};
var url = 'https://' + attendanceUsername + '.cloudant.com/' + user.id;
var db = new PouchDB(url, pouchOpts);
db.login(user2.name, user2.password, ajaxOpts).then(function() {
return db.allDocs();
}).then(function(docs) {
db.put(attendanceSecurity).then(function (response) {
// handle response
console.log(response);
}).catch(function (err) {
console.log(err);
});
console.log(docs);
}).catch(function(error) {
console.error(error);
});

Related

Node js writing bulk xml data to SQL Server

Need some assistance in node.js. Trying to update about 6000+ records into SQL Server. The records size maybe 5 to 10 MB. The xml records will be sent to the stored procedure which has a nvarchar(max) parameter. I am fetching records from a soap API call and push to SQL Server via a stored procedure.
I get an error when I run the below code if the record size is beyond 2000 in xml object. What is best way to send large xml objects of 5 to 10k to a SQL Server stored procedure?
Any nodejs library to handle this? Can nodejs handle such large records update ?
Note: this code will run inside aws lambda
var soap = require("strong-soap").soap;
var rfcUrl = https://xxxxxxxx/xxxx/xxxxx/xxxxx.asmx?WSDL;
var rfcRequestArgs = {
UserName:
Password:
};
var options = {};
console.log("Calling ervice...\n");
soap.createClient(rfcUrl, options, function(err, client) {
var method = client["GetLocationData"];
method(rfcRequestArgs, function(err, result, envelope, soapHeader) {
if(err) {
console.log('error: ' + err);
return;
}
else
{
//'result' is the response body
console.log('RFC Result: \n');
InitializeSQLConnection(JSON.stringify(result));
}
});
});
var connection = null;
function InitializeSQLConnection(LocData)
{
var Connection = require('tedious').Connection;
var config = {
server: 'ddddddddd', //update me
authentication: {
type: 'default',
options: {
userName: 'xxxxxxx', //update me
password: 'xxxxxxx' //update me
}
} ,
options: {
// If you are on Microsoft Azure, you need encryption:
encrypt: false,
database: 'DBName' //update me
}
};
connection = new Connection(config);
connection.on('connect', function(err) {
if (err) {
console.log('SQL Connection Failed!');
console.log(err);
throw err;
}
// If no error, then good to proceed.
console.log("SQL Server Connected");
executeStoredProcedure(LocData);
});
connection.connect();
}
function executeStoredProcedure(LocData)
{
console.log("calling executeStoredProcedure");
var Request = require('tedious').Request;
var TYPES = require('tedious').TYPES;
var loadTestState = 0;
var request = new Request('spname_new', function(err) {
connection.close();
});
request.addParameter('parameterrecords', TYPES.NVarChar, LocData);
request.addOutputParameter('returnVal', TYPES.Int);
request.on('returnValue', (paramName, value, metadata) => {
console.log(paramName + ' : ' + value);
});
connection.callProcedure(request);
console.log("Called SP");
}
'''

Connecting to Azure SQL using Service Principal in NodeJS, but token is rejected

I am having trouble getting my NodeJS application to connect to an Azure SQL Database using the Service Principal. However, when I try to do the same thing with a C# Snippet, it works fine. What I have noticed is that the tokens returned by the auth on both languages is a bit different, and if I take the correct token from C# and hard code it into NodeJS, my SQL Connection now succeeds.
I am first using ms-rest-azure to perform my authentication, and providing my clientId, tenantId and clientSecret. This returns back a valid credential, from which I am extracting the accessToken.
Then, I am using tedious to try to connect to the Azure SQL at *.database.windows.net and providing the accessToken value in the configuration.
I just get Login failed for user '<token-identified principal>'
What am I doing wrong in the ms-rest-azure login to give me a token that is rejected by Azure SQL? One thing I saw is that the working token has an audience of database.windows.net, where-as the one from ms-rest-azure is management.core.windows.net.
I've been stuck for a few days, if anybody has any clues here that would be awesome. The documentation on ms-rest-azure seems pretty non-existent and just gives you the runaround to Azure Sales pages.
const msRestAzure = require('ms-rest-azure');
const { reject } = require('async');
let clientSecret = "xxx";
let serverName = "xxx.database.windows.net";
let databaseName = "xxx";
let clientId = "xxx";
let tenantId = "xxx";
azureCredentials = msRestAzure.loginWithServicePrincipalSecret(clientId, clientSecret, tenantId, function(err, credentials) {
if (err) return console.log(err);
credentials.getToken((err, results) => {
if(err) return reject(err);
let accessToken = results.accessToken;
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var config = {
server: serverName,
authentication: {
type: 'azure-active-directory-access-token',
options: {
token: accessToken
}
}
,options: {
debug: {
packet: true,
data: true,
payload: true,
token: false,
log: true
},
database: databaseName,
encrypt: true
}
};
var connection = new Connection(config);
connection.connect();
connection.on('connect', function(err) {
if(err) {
console.log(err);
}
executeStatement();
}
);
connection.on('debug', function(text) {
console.log(text);
}
);
function executeStatement() {
request = new Request("select * from Text", function(err, rowCount) {
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
connection.close();
});
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
console.log(column.value);
}
});
});
request.on('done', function(rowCount, more) {
console.log(rowCount + ' rows returned');
});
connection.execSql(request);
}
});
})
when we use the certificates in the package ms-rest-azure to get token, In default, the token's audience is https://management.core.windows.net/, it just can be used to call Azure rest api. If we want to use Azure AD token to connect sql, the token's audience should be be https://database.windows.net/. So we should update the code used to get token as
msrestAzure.loginWithServicePrincipalSecret(
clientId,
clientSecret,
tenantId,
{
tokenAudience: "https://database.windows.net/",
},
For example
Create A service principal
az login
az ad sp create-for-rbac -n 'MyApp' --skip-assignment
Configure SQL Database
a. Use your Azure Sql AD admin to connect Azure SQL vai SSMS
b. Add the service principal to the database you need use
create user [<Azure_AD_principal_name>] from external provider
ALTER ROLE db_owner ADD MEMBER [<Azure_AD_principal_name>]
code
var msrestAzure = require("ms-rest-azure");
var { Connection, Request } = require("tedious");
let clientSecret = "xxx";
let serverName = "xxx.database.windows.net";
let databaseName = "xxx";
let clientId = "xxx";
let tenantId = "xxx";
async function getConnect() {
// way for Azure Service Principal
let databaseCredentials = await msrestAzure.loginWithServicePrincipalSecret(
clientId,
clientSecret,
tenantId,
{
tokenAudience: "https://database.windows.net/",
},
);
// getting access token
let databaseAccessToken = await new Promise((resolve, reject) => {
databaseCredentials.getToken((err, results) => {
if (err) return reject(err);
resolve(results.accessToken);
});
});
var config = {
server: serverName,
authentication: {
type: "azure-active-directory-access-token",
options: {
token: databaseAccessToken,
},
},
options: {
debug: {
packet: true,
data: true,
payload: true,
token: false,
log: true,
},
database: databaseName,
encrypt: true,
},
};
var connection = new Connection(config);
connection.connect();
connection.on("connect", function (err) {
if (err) {
console.log(err);
}
executeStatement(connection);
});
connection.on("debug", function (text) {
console.log(text);
});
}
function executeStatement(connection) {
request = new Request("select * from CSVTest", function (err, rowCount) {
if (err) {
console.log(err);
} else {
console.log(rowCount + " rows");
}
connection.close();
});
request.on("row", function (columns) {
columns.forEach(function (column) {
if (column.value === null) {
console.log("NULL");
} else {
console.log(column.value);
}
});
});
request.on("done", function (rowCount, more) {
console.log(rowCount + " rows returned");
});
connection.execSql(request);
}
getConnect()
.then(() => {
console.log("run successfully");
})
.catch((err) => {
console.log(err);
});
For more details, please refer to here

SQL select all statement in a node.js application returns a tedious deprecated error

So I went to the Microsoft documentation for node.js and trying to connect to a database and I went through step by step, installed tedious and when I try to run my code it's throwing an error saying:
tedious deprecated In the next major version of tedious, creating a new Connection instance will no longer establish a connection to the server automatically. Please use the new connect helper function or call the .connect method on the newly created Connection object to silence this message. internal\process\task_queues.js:79:11.
Does anyone know what this means?
CODE:
const Discord = require('discord.js');
const bot = new Discord.Client();
const token = 'HIDDEN';
bot.on('ready', () => {
console.log('This bot is online!');
var Connection = require('tedious').Connection;
var config = {
server: '', //update me
authentication: {
type: 'default',
options: {
userName: '', //update me
password: '' //update me
}
},
options: {
// If you are on Microsoft Azure, you need encryption:
encrypt: true,
database: '' //update me
}
};
var connection = new Connection(config);
connection.on('connect', function(err) {
// If no error, then good to proceed.
if(!err)
{
console.log("Connected");
executeStatement();
}
});
var Request = require('tedious').Request;
var TYPES = require('tedious').TYPES;
function executeStatement() {
request = new Request("SELECT * from tblCustomer;", function(err) {
if (err) {
console.log(err);}
});
var result = "";
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
result+= column.value + " ";
}
});
console.log(result);
result ="";
});
request.on('done', function(rowCount, more) {
console.log(rowCount + ' rows returned');
});
connection.execSql(request);
}
})
bot.login(token);

Web Digits Fabric Authentication

I am using digits web. I am using the cannonball example. I am running the below code on my local comptuter.
Heres my code of client side
<script>document.getElementById('digits-sdk').onload = function() {
Digits.init({ consumerKey: 'my consumer key' });
Digits.embed({
container: '#my-digits-container',
theme: {
/* Input fields borders */
},
phoneNumber: '+91',
})
.done(onLogin) /*handle the response*/
.fail(onLoginFailure);
};
function onLoginFailure(loginResponse) {
console.log('Digits login failed.');
//setDigitsButton('Verify again');
}
/* Validate and log use in. */
function onLogin(loginResponse){
// Send headers to your server and validate user by calling Digits’ API
//var oAuthHeaders = loginResponse.oauth_echo_headers;
var oAuthHeaders = parseOAuthHeaders(loginResponse.oauth_echo_headers);
$.ajax({
type: 'POST',
url: '/digits',
data: oAuthHeaders,
success: onDigitsSuccess
});
// setDigitsButton('Step 2.....');
}
function parseOAuthHeaders(oAuthEchoHeaders) {
var credentials = oAuthEchoHeaders['X-Verify-Credentials-Authorization'];
var apiUrl = oAuthEchoHeaders['X-Auth-Service-Provider'];
console.log(apiUrl);
return {
apiUrl: apiUrl,
credentials: credentials
};
}
function onDigitsSuccess(response) {
console.log(response.phoneNumber);
setDigitsNumber(response.phoneNumber);
}
function setDigitsNumber(phoneNumber) {
document.getElementById('notr').value = phoneNumber;
console.log('Digits phone number retrieved.');
}
</script>
In the above code I have changed the consumer key only. So ignore that.
And heres my server code
var express = require("express");
var app = express();
var router = express.Router();
var path = __dirname + '/static/';
app.use(express.static(__dirname + '/static'));
router.use(function (req,res,next) {
console.log("/" + req.method);
next();
});
router.get("/",function(req,res){
res.sendFile(path + "homepage9.html");
});
router.get("/about",function(req,res){
res.sendFile(path + "about.html");
});
router.get("/contact",function(req,res){
res.sendFile(path + "contact.html");
});
app.use("/",router);
app.use("*",function(req,res){
res.sendFile(path + "404.html");
});
app.listen(3000,function(){
console.log("Live at Port 3000");
});
var fs = require('fs');
var nconf = require('nconf');
var url = require('url');
var request = require('request');
router.post('/digits', function (req, res) {
console.log("digits entered")
var apiUrl = req.body['apiUrl']
var credentials = req.body['credentials']
var verified = true;
var messages = [];
if (credentials.indexOf('oauth_consumer_key="' + 'my consumer key' + '"') == -1) {
verified = false;
messages.push('The Digits API key does not match.');
}
var hostname = url.parse(req.body.apiUrl).hostname;
if (hostname != 'api.digits.com' && hostname != 'api.twitter.com') {
verified = false;
messages.push('Invalid API hostname.');
}
// Do not perform the request if the API key or hostname are not verified.
if (!verified) {
return res.send({
phoneNumber: "",
userID: "",
error: messages.join(' ')
});
}
// Prepare the request to the Digits API.
var options = {
url: apiUrl,
headers: {
'Authorization': credentials
}
};
// Perform the request to the Digits API.
request.get(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
// Send the verified phone number and Digits user ID.
var digits = JSON.parse(body)
return res.send({
phoneNumber: digits.phone_number,
userID: digits.id_str,
error: ''
});
} else {
// Send the error.
return res.send({
phoneNumber: '',
userID: '',
error: error.message
});
}
});
});
But on the node console i am getting
cannot read property 'apiUrl' of undefined.
on google chrome console i am getting
Failed to load resource: the server responded with a status of 500 (Internal Server Error)
Can any one help of what I am doing wrong.
Also in the cannon ball example i found that it nowhere uses the consumer secret key. Why is that?

Posting a Post through Facebook Graph Node JS

I'm currently looking to automate a few tasks by creating a custom application that allows me to easily post status updates on my Facebook page(not my personal timeline). My backend is running on NodeJS.
My client-side code has the following:
window.fbAsyncInit = function() {
FB.init({
appId : 'xxxxxxxxxxxxx', // App ID
channelUrl : '//xxxxxxxxxxx, // Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
// Additional init code here
FB.getLoginStatus(function(response) {
if (response.status === 'connected') {
console.log("You are signed into FB");
var access_token = FB.getAuthResponse()['accessToken'];
console.log('Access Token = ' + access_token);
FB.api('/me/accounts', function(response) {
for(var i=0;i <response.data.length;i++){;
var page = response.data[i];
if(page.id==my_id){
var page_token = page.access_token;
console.log(page_token);
var param = 'callback=?&username=' + GetURLParameter('username')+'&session='+ GetURLParameter('session')+'&access_token='+ page_token;
$.post(saveTokenEndpoint, param, function(data) {
console.log(data);
});
}
}
});
FB.api('/me', function(response) {
username = response.name;
userid = response.id;
$('#username').text('~Hi '+username+'!');
$(document).trigger('fbInit');
});
// connected
} else if (response.status === 'not_authorized') {
// not_authorized
login();
} else {
login();
// not_logged_in
}
});
};
// Load the SDK Asynchronously
( function(d) {
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {
return;
}
js = d.createElement('script');
js.id = id;
js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
function login() {
FB.login(function(response) {
if (response.authResponse) {
console.log("You are signed into FB");
var access_token = FB.getAuthResponse()['accessToken'];
FB.api('/me', function(response) {
username = response.name;
userid = response.id;
$('#username').text('~Hi '+username+'!');
$(document).trigger('fbInit');
});
FB.api('/me/accounts', function(response) {
// handle response
for(page in response.data){
if(page.id==my_id){
var page_token = page.access_token;
console.log(page_token);
var param = 'callback=?&username=' + GetURLParameter('username')+'&session='+ GetURLParameter('session')+'&access_token='+ page_token;
$.post(saveTokenEndpoint, param, function(data) {
console.log(data);
});
}
}
});
} else {
// cancelled
}
}, {scope: 'publish_stream, manage_pages, offline_access'});
}
My server-side code:
// saves the token received for future use in posting
app.post('/api/saveToken',function(req,res){
var username = req.body.username;
var access_token = req.body.access_token;
var session = req.body.session;
user.findOne({
username: username,
session: session
},function(err, userObj){
if(userObj!=null){
userObj.token = access_token;
console.log(access_token);
userObj.save();
res.jsonp({status:'true'});
}else{
res.jsonp({status:'false'});
}
});
});
I'm using this method to post my posts on my page:
var data = querystring.stringify({
access_token: token,
message: message
});
var options = {
host: 'graph.facebook.com',
port: 443,
path: '/app_name/feed',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': data.length
}
};
var req = https.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log("body: " + chunk);
});
res.on('end', function(){ // see http nodejs documentation to see end
console.log("\nfinished posting message");
conObj.approval = 'published';
conObj.save();
});
});
req.on('error', function(e) {
console.error(e);
});
req.write(data);
req.end();
Current situation:
My code is working and i can actually see the posts on the wall of my page.
BUT
It does not appear to anyone else except myself.
HOW I GOT IT TO APPEAR PROPERLY TEMPORARILY:
When i copy the token directly from the Graph API Explorer(/me/accounts), I got it to work.
https://developers.facebook.com/tools/explorer?method=GET&path=me%2Faccounts
Ultimately, all i want to do is find a way to post a post on my page
I monitored the differences that was made through both tokens and have found no differences. Their scope was to the 'public' and 'everyone'.
Experts do advice! I find this all very puzzling.
I'm intending to try NodeJS facebook such as facebook-node-sdk and nodejs-facebook-sdk libraries if all else fails.
Thanks for the replies in advance!
You should do OAUTH server side, not client side.
Here is a working example of posting a post through the Facebook Graph API using node.js here: http://code.runnable.com/facebook/UTlPM1-f2W1TAABY
The only dependency you're not already using is request, which you should be using.

Resources