CryptoJs is not decrypting URL on my NodeJS server - javascript

I am forwarding API calls from my frontend to my backend. I encrypt the API calls using CryptoJS.AES using the passphrase 'somekey'.
My relevant client code is...
var host = 'http://localhost:3000'
$('.send-button').click(function(){
var request = $('.request-input').val();
var encryptedRequest = CryptoJS.AES.encrypt(request, 'somekey');
console.log(encryptedRequest.toString())
var decryptedRequest = CryptoJS.AES.decrypt(encryptedRequest, 'somekey');
console.log('Decrypted Request: ' + decryptedRequest.toString());
handleRequest(encryptedRequest.toString());
});
var handleRequest = function(request){
$.ajax({
type: "GET",
url: host + '/requests?call=' + request,
success: function(data) {
var rawJSON = JSON.stringify(data, null, 2);
editor.setValue(rawJSON);
},
dataType: 'json'
});
}
relevant server side code is...
var port = 3000;
var serverUrl = "127.0.0.1";
var http = require("http");
var path = require("path");
var fs = require("fs");
var express = require("express");
var CryptoJs = require("crypto-js");
var app = express();
app.get('/requests', function(req, res) {
console.log('REQUEST: ' + req);
var call = req.query.call;
console.log(call)
console.log("To send: " + CryptoJs.AES.decrypt(call, 'somekey'));
});
The problem I keep getting is that it that when I decrypt it it either doesn't get the original URL and instead returns a bunch of jibberish. An example of this is...
Encryption: U2FsdGVkX1/NRbZkyP60pPu3Cb9IcQ4b9n4zJkExp2LNR3O1EdEpqHLNACnYuatN
Decryption: 68747470733a2f2f6e6577736170692e6f72672f76312f61727469636c6573
OR... It just returns nothing and appears blank.
Ideally I would like something like this.
Encryption: U2FsdGVkX1/NRbZkyP60pPu3Cb9IcQ4b9n4zJkExp2LNR3O1EdEpqHLNACnYuatN
Decryption: https://newsapi.org/v1/articles
Can anyone see what I am dong wrong?

Here is a working jsfiddle:
https://jsfiddle.net/5Lr6z4zp/1/
The encryption results in a Base64 string, while the decrypted string is Hex. To get back the “Message” you need to convert that to Utf8: decryptedRequest.toString(CryptoJS.enc.Utf8)
Here is the relevant part of the code that works:
var request = "testing decryption";
var encryptedRequest = CryptoJS.AES.encrypt(request, 'somekey');
console.log(encryptedRequest)
var decryptedRequest = CryptoJS.AES.decrypt(encryptedRequest, 'somekey');
var decryptedMessage = decryptedRequest.toString(CryptoJS.enc.Utf8)
console.log('Decrypted Request: ' + decryptedMessage);
Here is a link for a resources that explains the encryption/decryption in more detail:
http://www.davidebarranca.com/2012/10/crypto-js-tutorial-cryptography-for-dummies/

Related

NodeJS equivalent of C# code for hmac-sha256 authorization

Im trying to convert the C# code found here:
AMX Authorization Header in order to connect to an external API. The C# code works when trying to connect to the external API but when I convert it to a nodeJS solution it doesnt work.
I dont have access to the external C# API so can't update that side but was hoping someone could look at this and see something Im missing or doing wrong:
My nodejs solution:
var request = require('request');
var uuid = require('node-uuid');
var CryptoJS = require('crypto-js');
var URL = "https://urltoexternalAPI.com";
var itemAPPId = "testAPPId";
var APIKey = "testAPIKey";
var requestUri = encodeURIComponent(URL.toLowerCase());
var requestHttpMethod = "GET";
var requestTimeStamp = Math.floor(new Date().getTime() / 1000).toString();
var nonce = uuid.v1().replace(/-/g, '');
//I excluded the content hashing part as the API Im hitting is a GET request with no body content
var signatureRawData = itemAPPId + requestHttpMethod + requestUri + requestTimeStamp + nonce;
var secretKeyByteArray = CryptoJS.enc.Base64.parse(APIKey);
var signature = CryptoJS.enc.Utf8.parse(signatureRawData);
var signatureBytes = CryptoJS.HmacSHA256(signature, secretKeyByteArray);
var requestSignatureBase64String = signatureBytes.toString(CryptoJS.enc.Base64);
request({
url: URL,
headers: {
'Authorization': "amx "+itemAPPId+":"+requestSignatureBase64String+":"+nonce+":"+requestTimeStamp
}
}, function (error, response, body) {
if (response.statusCode != 200) {
console.log("Fail");
} else {
console.log("Success");
}
});
I figured it out! If anyone ever comes across this issue they may find the below helpful:
the following C# code works a little different to nodeJS:
System.Web.HttpUtility.UrlEncode(request.RequestUri.AbsoluteUri.ToLower());
Initially I copied this functionality as is and wrote the nodejs equivalent as such:
var requestUri = encodeURIComponent(URL.toLowerCase());
The encoding of the URL in C# keeps everything in lowercase - for e.g: https:// becomes https%3a%2f%2f - whereas nodeJS uppercases its encoding characters - https%3A%2F%2F - this is what as causing the incorrect hashing.
The solution is to just move the lowercase function to after the encoding has been done on the URL. Like so:
var requestUri = encodeURIComponent(URL).toLowerCase();
Seems rather simple but when trying to replicate the C# solution you may not pick up that the two URL encoders work differently.
Final solution: (updated to crypto thanks to Yoryo)
const fetch = require("node-fetch");
const uuid = require("uuid");
const crypto = require('crypto');
var URL = "https://urltoapi.com";
var itemAPPId = config.itemAPPId;
var APIKey = config.itemAPIKey;
var requestUri = encodeURIComponent(URL).toLowerCase();
var requestHttpMethod = "GET"; //should be dynamic
var requestTimeStamp = Math.floor(new Date().getTime() / 1000).toString();
var nonce = uuid.v1().replace(/-/g, '');
var signatureRawData = itemAPPId + requestHttpMethod + requestUri + requestTimeStamp + nonce;
var key = Buffer.from(APIKey, 'base64');
var requestSignatureBase64String = crypto.createHmac('sha256', key).update(signatureRawData, 'utf8').digest('base64');
const hitExternalAPI = async url => {
try {
const res = await fetch(url, { method: 'GET', headers: { "Authorization": "amx "+itemAPPId+":"+requestSignatureBase64String+":"+nonce+":"+requestTimeStamp } })
.then(res => {
console.log(res.ok);
});
} catch (error) {
console.log("Error",error);
}
};
hitExternalAPI(URL);

error 403 on nodejs when running .js file

help pls, I am trying to do a POST on my api but I am getting error 403, I read many topics but still not resolved my problem.
I am running my js file on nodejs prompt using comand: node myfilename.js to compile and getting this error. below is my code. I was supposed to get a json file back from the site I am trying to consume.
var app = require('./config/customs-express')();
var unirest = require('unirest');
var crypto = require('crypto');
var qs = require('querystring');
app.listen(3000, function() {
console.log('Server running door 3000');
});
var MB_TAPI_ID = 'xxx';
var REQUEST_HOST = 'https://www.xxxx.net';
var REQUEST_PATH = '/tapi/v3';
var MB_TAPI_SECRET = 'xxx';
var tapi_nonce = Math.round(new Date().getTime() / 1000);
var tapi_method = 'list_orders';
var params = (tapi_method, tapi_nonce);
var params_string = ((REQUEST_PATH) + '?' + (params));
var tapi_mac = crypto.createHmac('sha512', MB_TAPI_SECRET)
.update(tapi_method + ':' + MB_TAPI_SECRET + ':' +
tapi_nonce)
.digest('hex');
unirest.post(REQUEST_HOST)
.headers({'Content-type': 'application/x-www-form-urlencoded'})
.headers({'Key': MB_TAPI_ID})
.headers({'Sign': tapi_mac})
.send(qs.stringify({'method': tapi_method, 'tonce': tapi_nonce}))
.send(qs.stringify(params_string))
.end(function (response) {
console.log(response.body);
});
var app = require('./config/customs-express')();
var unirest = require('unirest');
var crypto = require('crypto');
var qs = require('querystring');
app.listen(3000, function() {
console.log('Server running door 3000');
});
403 means forbidden. The API is telling you "no."
If this works when you visit the page, it probably means they are using cookies. If that is the case, first hit the login page, get a cookie, then send the login request with the cookie. Superagent can do this, for example.

Print received data from client in NodeJS server

I have a simple html file containing that piece of javascript:
<script type="text/javascript">
$.ajax({
url: 'http://192.168.X.X:8080',
data: '{"data": "1"}',
dataType: "jsonp",
cache: false,
timeout: 5000,
success: function(data) {
var ret = jQuery.parseJSON(data);
},
error: function (xhr, status, error) {
console.log('Error: ' + error.message);
document.getElementById("error").innerHTML = 'Error: ' + error.message;
}
});
</script>
I simply want my NodeJS server to print data received (there: the number 1°).
Here is my NodeJS code:
var http = require('http');
var s = http.createServer();
s.on('request', function(request, response) {
response.writeHead(200);
console.log('a: '+request.method);
console.log('b: '+request.headers);
console.log('c: '+request.url);
});
s.listen(8080);
Server is receiving requests just find but how to retrieve the value of the data sent?
I just want server to receive a number from client and print it. How to do that?
Many thanks1
I think this does what your looking for.
#!/usr/bin/node
var http = require('http');
var s = http.createServer();
s.on('request', function(request, response) {
response.writeHead(200);
console.log('a: '+request.method);
console.log('b: '+request.headers);
console.log('c: '+request.url);
var url = decodeURIComponent(request.url);
var startPos = url.indexOf('{');
var endPos = url.indexOf('}');
var jsonString = url.substring(startPos, endPos+1);
json = JSON.parse(jsonString);
console.log(json['data'])
});
s.listen(8080);
If you just want to see jsonp works using the http module, you could use something like that (I wouldn't advise using this in any of your code, it's just for the demonstration):
var http = require('http');
var querystring = require('querystring');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
var query = querystring.parse(req.url.split('?')[1]);
console.log(query);
res.end(query.callback + '({"Name": "Foo", "Id": 1234, "Rank": 7})');
}).listen(8080);
Note: when using jquery jsonp data should better be an object, not a string (see https://learn.jquery.com/ajax/working-with-jsonp/)
You should, however, ask yourself:
Why jsonp?
Is there a module that does all that for you & parse JSON, help you with errors/authentication/etc? I usually use https://www.npmjs.com/package/hapi (It supports jsonp if you really need it), there other modules like express.

Express.js proxy pipe translate XML to JSON

For my front-end (angular) app, I need to connect to an external API, which does not support CORS.
So my way around this is to have a simple proxy in Node.JS / Express.JS to pass the requests. The additional benefit is that I can set my api-credentials at proxy level, and don't have to pass them to the front-end where the user might steal/abuse them.
This is all working perfectly.
Here's the code, for the record:
var request = require('request');
var config = require('./config');
var url = config.api.endpoint;
var uname = config.api.uname;
var pword = config.api.pword;
var headers = {
"Authorization" : 'Basic ' + new Buffer(uname + ':' + pword).toString('base64'),
"Accept" : "application/json"
};
exports.get = function(req, res) {
var api_url = url+req.url;
var r = request({url: api_url, headers: headers});
req.pipe(r).pipe(res);
};
The API-endpoint I have to use has XML as only output format. So I use xml2js on the front-end to convert the XML reponse to JSON.
This is also working great, but I would like to lighten the load for the client, and do the XML -> JSON parsing step on the server.
I assume I will have to create something like:
req.pipe(r).pipe(<convert_xml_to_json>).pipe(res);
But I don't have any idea how do create something like that.
So basically I'm looking to create an XML to JSON proxy as a layer on top of an already existing API.
There are a lot of questions on SO regarding "how do I make a proxy" and "how do I convert XML to JSON" but I couldn't find any that combine the two.
you need to use transform stream and for xml to json conversion you need some library i use this xml2json
..then u use it like this (simplified but it should work with request too)
var http = require('http');
var fs = require('fs');
var parser = require('xml2json');
var Transform = require('stream').Transform;
function xmlParser () {
var transform = new Transform();
transform._transform = function(chunk, encoding, done) {
chunk = parser.toJson(chunk.toString())
console.log(chunk);
this.push(chunk);
done();
};
transform.on('error', function (err) {
console.log(err);
});
return transform;
}
var server = http.createServer(function (req, res) {
var stream = fs.createReadStream(__dirname + '/data.xml');
stream.pipe(xmlParser()).pipe(res);
});
server.listen(8000);

How to do a simple read POST data in Node JS?

I've used this code to read the querystring ?name=Jeremy ...can anyone tell me how to do this with post data? also with json?
var http = require('http'), url = require('url');
http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type":"text/plain"});
var urlObj = url.parse(request.url, true);
response.write("Hello " + urlObj.query["name"] + "!\n");
}).listen(8000);
thanks!
You have to handle data and end events of http.ServerRequest object. Example:
var util = require("util"),
http = require('http'),
url = require('url'),
qs = require('querystring');
...
// this is inside path which handles your HTTP POST method request
if(request.method === "POST") {
var data = "";
request.on("data", function(chunk) {
data += chunk;
});
request.on("end", function() {
util.log("raw: " + data);
var json = qs.parse(data);
util.log("json: " + json);
});
}
Here is an article on this topic with example (with too old version of node.js so it might not work, but the principle is the same).

Categories

Resources