Meteor routing for nonUTF encoded POST request - post

I am implementing REST API for merchant system. This merchant system sends payment confirmation POST request to my system to specified URL, and this request is encoded in windows-1251.
I've tried iron-router and restivus to handle this request, both of them failed with error
UnsupportedMediaTypeError: unsupported charset "WINDOWS-1251"
at Object.urlencodedParser [as handle] (/home/dev/builds/bundle/programs/server/npm/node_modules/meteor/simple_json-routes/node_modules/connect/node_modules/body-parser/lib/types/urlencoded.js:102:12)
at next (/home/dev/builds/bundle/programs/server/npm/node_modules/meteor/webapp/node_modules/connect/lib/proto.js:174:15)
at middleware (packages/oauth.js:107:7)
at packages/oauth.js:96:5
My current iron router code:
Router.route('/api/payments/result/',{where: "server", name: 'payments-result'})
.post(function () { });
Router.onBeforeAction(function (req, res, next) {
logger.info('GOT A CONFIRMATION REQUEST');
logger.info(`request headers are: ${req.rawHeaders}`);
logger.info('request is: ');
Object.keys(req.body).forEach(key => {
let val = req.body[key];
logger.info(`${key} : ${val}`);
});
res.end('hello from the server\n');
},{where: 'server', only: ['payments-result']});
None of log statements are executed even during onBeforeAction hook.
The question is how to setup correct request decoding or to avoid body-parser that accepts only utf-8 encoded request, as I've found out.
UPDATE
Ad hock solution was to convert win-1251 to utf8 using nginx

Ad hock solution was to convert win-1251 to utf8 using nginx.

Related

Cannot POST with ESP8266 (espruino)

I cannot make post request (get works fine) with espruino.
I've already checked the documentation and it seems pretty equal
here is my code:
let json = JSON.stringify({v:"1"});
let options = {
host: 'https://******,
protocol: 'https',
path: '/api/post/*****',
method: 'POST',
headers:{
"Content-Type":"application/json",
"Content-Length":json.length
}
};
let post = require("http").request(options, function(res){
res.on('data', function(data){
console.log('data: ' + data);
});
res.on('close', function(data){
console.log('Connection closed');
});
});
post.end(json);
The espruino console only return the 'connection closed' console.log.
The node.js server console (hosted on heroku and tested with postman) dont return anything.
Obv the esp8266 is connected to the network
What you're doing looks fine (an HTTP Post example is here), however Espruino doesn't support HTTPS on ESP8266 at the moment (there isn't enough memory on the chips for JS and HTTPS).
So Espruino will be ignoring the https in the URL and going via HTTP. It's possible that your server supports HTTP GET requests, but POST requests have to be made via HTTPS which is why it's not working?
If you did need to use HTTPS with Espruino then there's always the official Espruino WiFi boards, or I believe ESP32 supports it fine too.
you're using a package called "http" and then trying to send a request over https. You should also log out 'data' in the res.close so you can get some errors to work with.

BigCommerce oAuth auth token request always returning 401

I can not figure out what I'm doing wrong. I'm developing an App for BigCommerce and can not get the simple oAuth exchange to work correctly.
The initial get request is being made to https://www.my-app.com/oauth/bigcommerce/auth. This is the code in the controller for that request. It's a Laravel 5.6 app:
use Illuminate\Http\Request;
use Bigcommerce\Api\Client as Bigcommerce;
class BigcommerceOAuthController extends Controller
{
public function auth(Request $request)
{
$object = new \stdClass();
$object->client_id = 'my-client-id';
$object->client_secret = 'my-client-secret';
$object->redirect_uri = 'https://my-app.com/oauth/bigcommerce/auth';
$object->code = $request->get('code');
$object->context = $request->get('context');
$object->scope = $request->get('scope');
$authTokenResponse = Bigcommerce::getAuthToken($object);
$storeHash = str_replace('stores/', '', $request->get('context'));
Bigcommerce::configure(array(
'client_id' => 'my-client-id',
'auth_token' => $authTokenResponse->access_token,
'store_hash' => $storeHash
));
echo "<pre>";
print_r($authTokenResponse);
print_r(Bigcommerce::getTime());
echo "</pre>";
}
}
Every time I try to install my draft app from the BigCommerce control panel, I get an error because $authTokenResponse is not an object. When I debug further into the Bigcommerce\Api\Connection class, I can see that the response from the server is empty, and the status is a 401, which means "Unauthorized".
I can't figure out why I am getting this error. As far as I can see, I'm doing everything right. I've tried urlencoding the string retrieved from $request->get('scope'), since that string becomes unencoded by Laravel, but that didn't seem to help.
I am also confused how this is even supposed to work at all. In the BigCommerce docs, they show this example POST request, which uses application/x-www-form-urlencoded Content-Type and passes the request body as a url encoded string:
POST /oauth2/token HTTP/1.1 Host: login.bigcommerce.com Content-Type:
application/x-www-form-urlencoded Content-Length: 186
client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&code=qr6h3thvbvag2ffq&scope=store_v2_orders&grant_type=authorization_code&redirect_uri=https://app.example.com/oauth&context=stores/{STORE_HASH}
However, if you inspect what's going on in the Connection class, you can see that the Content-Type is being set to application/x-www-form-urlencoded as the docs say, but the request body is being passed in as a json string, not a url string. Shouldn't the request be a url encoded string as the docs suggest?
A couple of things here to check:
Do you have a public URL where you can receive the Auth Callback?
If so, did the store owner registered the app successfully? https://developer.bigcommerce.com/api/registration
When you have the client_id and secret_id. You should have all of the details needed to send a POST request to the BC Auth Token Service at https://login.bigcommerce.com/oauth2/token
The content uses URL encode Make sure to URL encode your content. Be careful of of the encoding of & and = signs when those are actually being used as separators.
More details can be found in this post:
Can BigCommerce Private Apps use OAuth

Neo4j simple authentication

I can log in using username and password here http://localhost:7474/ by typing server: connect and logging in. I can view data from there by executing queries.
Then I immediately switch to a new tab, or in the same tab, and go to: http://localhost:7474/db/data/, and I get:
{
"errors" : [ {
"message" : "No authorization header supplied.",
"code" : "Neo.ClientError.Security.AuthorizationFailed"
} ]
}
And I cannot connect using py2Neo or any NEO4J libraries either using the same password; they return the exact same error.
What am I doing wrong?
add this to your http-headers request:
Authorization: "Basic xxxx"
xxxx = base64(username:password)
All REST API requests must now include the Authorization header. To quote the REST API Authentication and Authorization page of the neo4j manual:
Requests should include an Authorization header, with a value of Basic
<payload>, where "payload" is a base64 encoded string of
"username:password".
That page contains some examples.
Note: you can also disable authentication -- but you should only do this on your personal machine, for development purposes. You do this by setting to false the dbms.security.auth_enabled property in <neo4j-install-dir>/conf/neo4j-server.properties, and then restarting the server.
[UPDATED]
By the way, since your question mentioned py2neo, you should know that its Graph class supports "authorisation".
The request json should look like: (XXX being the Base64 encoding of the user:password string - the string to encode contains the column):
{
method: "POST",
headers: {
"content-type": "application/json",
"Authorization": "Basic XXX"
},
body: {
statements:[
{
statement: query,
parameters: params
}
]
}
}
This has been tested in Javascript (axios) and in Deno.land (fetch API). ES Javascript contains a built in base64 encoding function: btoa()

Alamofire http request to local webserver

I'm developing an iPhone app and the plan is to send a JSON packet every so often from the app to a local webserver. To do this, I had planned to use Alamofire. My POST method looks like this:
Alamofire.request(Alamofire.Method.POST, "http://XXX.XX.X.XX:3000/update", parameters: dictPoints, encoding: .JSON)
.responseJSON {(request, response, JSON, error) in
println(JSON)
}
The IP address is marked out, but I've made sure that this corresponds to the IPv4 wireless address of my local server. The server is set to listen to port 3000. The server configuration looks like this:
var express = require('express');
var app = express();
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function (callback) {
console.log("MongoDB connection is open.");
});
// Mongoose Schema definition
var Schema = mongoose.Schema;
var LocationSchema = new Schema({
//some schema here
});
// Mongoose Model definition
var LocationsCollection = mongoose.model('locations', LocationSchema);
// URL management
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
app.get('/update', function (req, res) {
console.log("Got something from the phone!");
});
// Start the server
var server = app.listen(3000, function () {
var host = server.address().address
var port = server.address().port
console.log('App listening at %s:%s',host, port)
})
So, this server seems to work ok. I can test it in my browser and type the URL: http://127.0.0.1:3000 and it will feed me the index.html file. If I type in http://127.0.0.1:3000/update... then I get the "Got something from the phone!" message. However, when I run my app (making sure my phone is on the same wireless network as the server) and the Alamofire method gets called... the response I get is nil. I also don't see the "Got something from the phone!" message. Can anyone let me know why that would be happening... or better yet, how to fix it?
A few thoughts:
You are creating a POST request in Alamofire, but you've told Express to handle GET requests for /update. Use app.post(...) if you want to handle it as a POST.
Your Alamofire code is looking for JSON response, but you don't appear to be creating a JSON response. In the short term, you could use responseString rather than responseJSON, but I presume you really want to change your web service to respond with JSON (to make it easier for the app to parse the responses).
Your Alamofire code sending a JSON request (but clearly when you send a request via the web browser, it's not JSON). Are you sure you wanted to send JSON request? (This is not to be confused with the JSON response issue.) Did you want to use the .URL encoding type parameter, rather than .JSON?
Whenever you have a request that works correctly from a web browser, but not from the app, it's useful to watch both using a tool like Charles and you can then compare how they differ and diagnose the source of the different behavior.
If you are running Express server and iOS Simulator on the same machine, try to use http://0.0.0.0:<port>/<url> instead of the actual IP, it helped in my case.
It sounds like the node server is not bound to the address you expect it to be. You should verify that when you type in the actual IP address in your "http://XXX.XX.X.XX:3000/update" in your web browser that it responds. Your question details suggest you've just been using the loopback address.

POST request and Node.js without Nerve

Is there any way to accept POST type requests without using Nerve lib in Node.js?
By default the http.Server class of Node.js accepts any http method.
You can get the method using request.method (api link).
Example:
var sys = require('sys'),
http = require('http');
http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.write(request.method);
response.end();
}).listen(8000);
sys.puts('Server running at http://127.0.0.1:8000/');
This will create a simple http server on the port 8000 that will echo the method used in the request.
If you want to get a POST you should just check the request.method for the string "POST".
Update regarding response.end:
Since version 0.1.90, the function to close the response is response.end instead of response.close. Besides the name change, end can also send data and close the response after this data is sent unlike close. (api example)

Resources