So I'm new to OAuth and Node.JS, but I have to create a Flickr bot to upload photos for a university project. From my understanding Node doesn't have native support of multipart/formdata requests so I constructed the POST request manually.
I know the following code isn't necessarily clean or best-practice, but it's meant to be a one-off hack: the server is being requested by a single computer and only running for a few hours.
this.post = function(text, image) {
var me = this;
if (me.authenticated) {
fs.readFile(image, 'utf8', function(err,data) {
if (err) throw new Error(err);
var bound = (crypto.createHash('md5').update((Math.random()*9999999).toString()).digest('hex'));
var req = http.request({host:'api.flickr.com',port:80,path:'/services/upload/',method:'POST',
headers:{
'Content-Type':'multipart/form-data; boundary='+bound,
'Content-Length':data.length,
'Connection':'keep-alive'
}
}, function(res) {
res.setEncoding('utf8');
res.on('data', function(chunk) {
console.log(chunk);
});
console.log(me);
});
bound = "--"+bound;
req.on('error', function(msg) {console.log('FLICKR UPLOAD ERROR: '+msg.message);});
req.write(bound+"\r\n");
req.write('Content-Disposition: form-data; name="api_key"\r\n\r\n'+flickroptions.key);
req.write("\r\n"+bound+"\r\n");
console.log("sending token "+me.token);
req.write('Content-Disposition: form-data; name="auth_token"\r\n\r\n'+me.token);
req.write("\r\n"+bound+"\r\n");
req.write('Content-Disposition: form-data; name="api_sig"\r\n\r\n'+function() {
var str = 'api_key'+flickroptions.key;
str += 'api_token'+me.token;
return crypto.createHash('md5').update(str).digest('hex');
}());
req.write("\r\n"+bound+"\r\n");
req.write('Content-Disposition: form-data; name="photo"; filename="'+image+'"\r\n');
req.write('Content-Type: image/jpeg\r\n\r\n');
req.write(data);
req.write('\r\n'+bound+"--"); req.end();
});
}
}
The above function generates a POST request more or less the same as recommended in the documentation. But for some reason, the request responds saying that auth_token is invalid.
I'm setting up authentication with the following two functions:
this.init = function(text,image) {
var me = this;
fauth.getOAuthRequestToken({'oauth_callback':'http://192.168.0.19:7001/flickr'}, function(err, token, secret, results) {
if (err) console.log(err);
if (token && secret) {
me.secret = secret; me.token = token;
me.location = 'http://flicker.com/services/oauth/authorize?perms=write&oauth_token='+token;
}
});
}
//?oauth_token&oauth_verifier
this.auth = function(token, verifier) {
var me = this;
this.token = token; this.verifier = verifier;
fauth.getOAuthAccessToken(this.token, this.secret, this.verifier, function(err,token,secret,results) {
if (err) {console.log(err); return;}
me.results = results; me.authenticated = true;
me.token = token;
me.secret = secret;
me.post('hello world', '../eyes/memory/eyes000001.jpg');
});
}
Where this.init gets a Flickr authentication page and this.auth processes the redirected callback and then calls this.post. fauth is an instance of node-oauth. Am I missing a step in the process or have I messed up along the way? Thanks.
When using OAuth you no longer us the api_key, api_sig and auth_token parameters anymore, even for uploading. You should be using oauth_consumer_key, oauth_signature and oauth_token instead.
An OAuth Token is not a valid old style auth_token, and vice versa.
Check out my blog series on Flickr and OAuth for more details: http://www.wackylabs.net/2011/12/oauth-and-flickr-part-1/
Related
I need to read the raw text of a file in my Github private repo so I generated a Personal Access Token and am making a request to the raw version of the file, but get a 404 response code. I've tried a lot of variations of this request code, but always get a 404.
const https = require('https');
let options = {}
let url = 'https://raw.githubusercontent.com/account/repo/branch/filename.json';
options.headers = { Authorization: 'token ghp_personal-access-token'}
try {
let body = await promiseHttpsRequest(url, options);
let remoteFile = JSON.parse(body);
} catch(err) {
if (err = 404) throw new Error('This repository requires a token or does not exist. \n ' + url);
throw err; // 404 ERROR IS THROWN HERE
}
function promiseHttpsRequest(url, options) {
return new Promise(function(resolve, reject) {
let req = https.request(url, options, res => {
let body = '';
res.on('data', data => {body += data});
res.on('end', function() {
if (res.statusCode == '200') return resolve(body);
reject(res.statusCode);
});
});
req.on('error', reject);
req.end();
});
}
When I use cURL to test it, I get the file contents just fine so I know the general token-based approach should work.
curl https://raw.githubusercontent.com/account/repo/branch/filename.json -H "Authorization: token ghp_personal-access-token"
After banging my head against this for a day, I ended up hacking together a curl request using exec() and it works. It's not an ideal solution, but I need to move on.
I welcome any insight into what I'm doing wrong with the first approach. I'm still new to nodeJS and suspect I'm missing something simple here.
So I think I have this correct but for some reason it is not executing the way I would think. I am just wanting to decode the JWT Token and pass the data back. Here is the code:
var jwtToken = function(message, callback) {
var tokenArray = message.headers['authorization'];
var array = tokenArray.toString().split(' ');
if (array[0] == 'Bearer') {
var token = array[1];
} else {
return callback.status(401).json({message: "bad json token"});
}
var map = JSON.parse(process.env.AUTH0_SECRET);
var decoded = jwt2.decode(token, {complete: true});
console.log('PAYLOAD:');
console.log(decoded.payload);
var clientId = decoded.payload.aud;
var secret = map[clientId];
//console.log('ENVIRONMENT SECRET: ' + map);
//console.log('CLIENT ID: ' + clientId);
//console.log('MAPPED SECRET: ' + secret);
jwt2.verify(token, secret, function(err, decode){
if (err) {
callback.status(401).json({message: "JSON is incorrect or expired"})
} else {
callback = decode;
}
});
};
//route to make sure that the API works
app.get('/', function(req,res) {
jwtToken(req, function(data){
console.log(data);
res.json({ message: 'You are connected to the API ' + data})
});
});
What I would expect is that I pass in the request into the jwtToken function and I would get back the decoded Token in the callback. I would then send the Response with the message and the decoded Token. What I am getting is the data in the logs from the jwtToken call but then it keeps running till it times out. I am just not sure what I messed up in the Callback that would stop it from sending the result back. Thanks for your help.
You're not calling the callback anywhere. Just assigning it to decode. You need to do:
callback(decode);
Assuming decode is the value that you want in your data in the callback.
I'm making a NodeJS app which should download a file given the public share URL that doesn't request login auth.
I have created the app inside the developer section and generated the proper tokens.
On the git documentation I've found this method that should be used to download a file. The first parameter is the fileId but I don't find written anywhere what this id is and where to find it.
https://rawgit.com/box/box-node-sdk/master/docs/jsdoc/Files.html#getReadStream
I've tried this code
var fs = require('fs'),
BoxSDK = require('box-node-sdk'),
sdk = new BoxSDK({
clientID: '...',
clientSecret: '...'
}),
client = sdk.getAnonymousClient(),
file_id = process.argv[2].replace(/\S*\/(\S+)$/,"$1");
client.files.getReadStream(file_id, null, function(error, stream)
{
if (error) {
throw error;
}
// write the file to disk
var output = fs.createWriteStream('./output/'+file_id+".zip"); //I know for sure there will only be zip files
stream.pipe(output);
});
But running it with this command
nodejs index.js https://adrime.box.com/s/s5w7lzm4xfifmxrod9r7eeniv9nhtenk
I get this error:
Error: Unexpected API Response [404 Not Found] (not_found: "Not Found")
at Object.module.exports.buildResponseError (/home/andrea/dev/node/box_api/node_modules/box-node-sdk/lib/util/errors.js:57:23)
at Object.module.exports.buildUnexpectedResponseError (/home/andrea/dev/node/box_api/node_modules/box-node-sdk/lib/util/errors.js:94:15)
at /home/andrea/dev/node/box_api/node_modules/box-node-sdk/lib/managers/files.js:148:20
at BoxClient._handleResponse (/home/andrea/dev/node/box_api/node_modules/box-node-sdk/lib/box-client.js:291:2)
at handleResponseCallback (/home/andrea/dev/node/box_api/node_modules/box-node-sdk/lib/box-client.js:233:9)
at /home/andrea/dev/node/box_api/node_modules/box-node-sdk/lib/api-request.js:285:3
at nextTickCallbackWith0Args (node.js:436:9)
at process._tickCallback (node.js:365:13)
Can anyone help me in programmatically downloading a public shared file from box.com?
Thank you in advance!
At the moment I've found this solution.
To me it works pretty well. I hope it will be useful to others as well.
var fs = require("fs"),
request = require("request");
function downloadFile(source, target, callback)
{
var wr = fs.createWriteStream(target);
wr.on("error", function (err)
{
callback(err);
});
wr.on("close", function (ex)
{
callback();
});
request
.get(source)
.on("error",function(err)
{
callback(err);
})
.on('response', function(response)
{
if((""+response.statusCode).charAt(0) != "2")
callback({
msg: "File not found: "+response.request.href,
path: response.request.href,
toString: function(){
return this.msg;
}
});
})
.on("end", function (ex)
{
console.log("request ended");
})
.pipe(wr);
}
function onDownloadComplete(err)
{
if(err)
throw err;
console.log("DOWNLOAD COMPLETE");
}
function init()
{
var static_url = process.argv[2].replace(/\/s\//,"/shared/static/") + ".zip";
console.log(static_url);
downloadFile(static_url, "./output/template.zip", onDownloadComplete);
}
init();
I would like to use the Bing Speech Recognition API to convert speech to text when sending audio attachments in Skype to my node.js chatbot. I have tried using the code from BotBuilder-Samples intelligence-SpeechToText, however the speech recognition only works in the Emulator. When sending an audio/wave file in Skype, the bot does not respond at all instead of "You said: What’s the weather like?".
I suspected that the issue might be due to the fact that a JWT Token is required to access attachments in Skype. Hence, I have tried accessing the audio attachment in Skype using the code from BotBuilder-Samples core-ReceiveAttachment which uses request-promise instead of needle to make the HTTP request. However, the result from request-promise is not a stream and cannot be processed by the function getTextFromAudioStream().
I there would like to ask how to get speech recognition to work with audio attachments in Skype.
Thanks and best regards!
// Add your requirements
var restify = require("restify");
var builder = require("botbuilder");
var fs = require("fs");
var needle = require("needle");
var request = require("request");
var speechService = require("./speech-service.js");
var Promise = require('bluebird');
var request = require('request-promise').defaults({ encoding: null });
//=========================================================
// Bot Setup
//=========================================================
// Setup Restify Server
var server = restify.createServer();
server.listen(process.env.PORT || 3000, function() {
console.log("%s listening to %s", server.name, server.url);
});
// Create chat bot
var connector = new builder.ChatConnector ({
appId: process.env.MICROSOFT_APP_ID,
appPassword: process.env.MICROSOFT_APP_PASSWORD
});
server.post("/api/messages", connector.listen());
var bot = new builder.UniversalBot(connector);
//=========================================================
// Bots Middleware
//=========================================================
// Anytime the major version is incremented any existing conversations will be restarted.
bot.use(builder.Middleware.dialogVersion({ version: 1.0, resetCommand: /^reset/i }));
//=========================================================
// Bots Dialogs
//=========================================================
bot.dialog("/", [
function (session, results, next) {
var msg = session.message;
if (hasAudioAttachment(msg)) {
// Message with attachment, proceed to download it.
// Skype attachment URLs are secured by a JwtToken, so we need to pass the token from our bot.
var attachment = msg.attachments[0];
var fileDownload = isSkypeMessage(msg)
? requestWithToken(attachment.contentUrl)
: request(attachment.contentUrl);
fileDownload.then(
function (response) {
// Send reply with attachment type & size
var reply = new builder.Message(session)
.text('Attachment from %s of %s type and size of %s bytes received.', msg.source, attachment.contentType, response.length);
session.send(reply);
}).catch(function (err) {
console.log('Error downloading attachment:', { statusCode: err.statusCode, message: err.response.statusMessage });
});
var stream = isSkypeMessage(msg)
? getAudioStreamWithToken(attachment)
: getAudioStream(attachment);
speechService.getTextFromAudioStream(stream)
.then(text => {
session.send("You said: " + text);
})
.catch(error => {
session.send("Oops! Something went wrong. Try again later.");
console.error(error);
});
}
else {
session.send("Did you upload an audio file? I'm more of an audible person. Try sending me a wav file");
}
}
]);
function getAudioStream(attachment) {
return needle.get(attachment.contentUrl, { headers: {'Content-Type': "audio/wav"} });
}
function getAudioStreamWithToken(attachment) {
var headers = {};
connector.getAccessToken((error, token) => {
headers['Authorization'] = 'Bearer ' + token;
});
headers['Content-Type'] = attachment.contentType;
return needle.get(attachment.contentUrl, { headers: headers });
}
// Request file with Authentication Header
function requestWithToken(url) {
return obtainToken().then(function (token) {
return request({
url: url,
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/octet-stream'
}
});
});
};
// Promise for obtaining JWT Token (requested once)
var obtainToken = Promise.promisify(connector.getAccessToken.bind(connector));
function isSkypeMessage(message) {
return message.source === "skype";
};
The code in the sample is already considering Skype when accessing to the attachments (see here). I think the problem you were hitting is because the key in the sample exceeded the quota. Yesterday a new Bing Speech Key was added to the sample, so I would suggest you to try again.
Also, an updated version of the sample is going to be added soon. The code is currently under code review.
in my project I have to do a request to upcDatabase.com, I amworking with nodeJS, I get the answer from the server but I do not how to extractthe data this are the important part of my code:
module.exports = function (http,upc){
var upc_ApiKey = "XXX",
url = "http://upcdatabase.org/api/json/"+upc_ApiKey+'/'+upc;
http.get(url,function(resp){
// my code to read the response
I do not get any error, but the resp is a big Json and I do not know where to find the data
I would recommend you using the superagent module. It provides much more functionality than the built-in http request and it will automatically parse the response for you.
request
.get(url)
.end(function(err, res) {
if (res.ok) {
// Her ethe res object will be already parsed. For example if
// the server returns Content-Type: application/json
// res will be a javascript object that you can query for the properties
console.log(res);
} else {
// oops, some error occurred with the request
// you can check the err parameter or the res.text
}
});
You could achieve the same with the built-in http module but with much more code:
var opts = url.parse(url);
opts.method = "GET";
var req = http.request(opts, function (res) {
var result = "";
res.setEncoding("utf8");
res.on("data", function (data) {
result += data;
});
if (res.statusCode === 200) {
res.on("end", function () {
// Here you could use the result object
// If it is a JSON object you might need to JSON.parse the string
// in order to get an easy to use js object
});
} else {
// The server didn't return 200 status code
}
});
req.on("error", function (err) {
// Some serious error occurred during the request
});
// This will send the actual request
req.end();