check if api token exists in header in javascript - javascript

I am trying to test if an API token exists in my API call. the headers being passed to are -
"host": [
{
"key": "Host",
"value": "mydomain"
}
],
"x-api-key": [
{
"key": "x-api-key",
"value": "mykey"
}
]
}
Now my code looks like
// Check if apikey is a part of the headers
if ( !headers.hasOwnProperty('x-api-key') || headers['x-api-key'][0].value!="mykey") {
const body = 'Unauthorized';
const response = {
status: 401,
statusDescription: 'Unauthorized',
body: body,
};
callback(null, response);
}
My If case errors out instead of sending 401 if the headers are missing x-api-key altogether
"errorMessage": "Cannot read property '0' of undefined",
How should i change my condition so i can check for both the key/value pair and not have undefined errors incase of missing header key/value

Try updating your code to
// Check if apikey is a part of the headers
if ( !headers.hasOwnProperty('x-api-key') || (headers.hasOwnProperty('x-api-key') && headers['x-api-key'][0].value!="mykey")) {
const body = 'Unauthorized';
const response = {
status: 401,
statusDescription: 'Unauthorized',
body: body,
};
callback(null, response);
}
Your first condition checks if x-api-key exists in the headers. And the second condition checks the value for the x-api-key.
The way OR works is that it will stop its execution either at the first occurence of a true condition or will process each condition. Thus in your case, if x-api-key is not passed as a header, it still goes and checks the second condition. Since the x-api-key does not exist, it will not be able to read [0] of the property and hence the error.
However AND stops its execution at the first occurence of a false condition, and hence will never process the second condition if the x-api-key is not a part of the headers.

Related

Paypal Checkout client integration - Problem with returning order id promise

i have a problem integrating paypals payment gateway. I am using javascript for the client, python for the backend and the checkouts v2 api.
Creating a order on the backend works without trouble, but while waiting for my servers response the createOrder function raises a error:
unhandled_error
Object { err: "Expected an order id to be passed\nLe/</<#https://www.sandbox.paypal.com/smart/buttons?style.layout=vertical&style.color=blue&style.shape=rect&style.tagline=false&components.0=buttons&locale.country=NO&locale.lang=no&sdkMeta=eyJ1cmwiOiJodHRwczovL3d3dy5wYXlwYWwuY29tL3Nkay9qcz9jbGllbnQtaWQ9QWJmSjNNSG5oMkFIU1ZwdXl4eW5lLXBCbHdJZkNsLXpyVXc1dzFiX29TVUloZU01LXNMaDNfSWhuTnZkNUhYSW5wcXVFdm5MZG1LN0xOZ1gmZGlzYWJsZS1mdW5kaW5nPWNyZWRpdCxjYXJkIiwiYXR0cnMiOnt9fQ&clientID=AbfJ3MHnh2AHSVpuyxyne-pBlwIfCl-zrUw5w1b_oSUIheM5-sLh3_IhnNvd5HXInpquEvnLdmK7LNgX&sessionID=e2ea737589_mtc6mtu6mdi&buttonSessionID=de4bfb3626_mtc6mjm6mtk&env=sandbox&fundingEligibility=eyJwYXlwYWwiOnsiZWxpZ2libGUiOnRydWV9LCJjYXJkIjp7ImVsaWdpYmxlIjpmYWxzZSwiYnJhbmRlZCI6dHJ1ZSwidmVuZG9ycyI6eyJ2aXNhIjp7ImVsaWdpYmxlIjp0cnVlfSwibWFzdGVyY2FyZCI6eyJlbGlnaWJsZSI6dHJ1ZX0sImFtZXgiOnsiZWxpZ2libGUiOnRydWV9LCJkaXNjb3ZlciI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJoaXBlciI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJlbG8iOnsiZWxpZ2libGUiOmZhbHNlfSwiamNiIjp7ImVsaWdpYmxlIjpmYWxzZX19…", timestamp: "1593537805136", referer: "www.sandbox.paypal.com", sessionID: "e2ea737589_mtc6mtu6mdi", env: "sandbox", buttonSessionID: "de4bfb3626_mtc6mjm6mtk" }
Error: Expected an order id to be passed
Error: Expected an order id to be passed
12V21085461823829 // ticks in a few seconds later
Console screenshot
The problem seems to be that createOrder does not wait for the promise before raising the error, or that the promise is not given in the correct way. Something like that. Anyways here is the client side code:
paypal.Buttons({
// button styling removed for clarity
createOrder: function() {
// purchase information
var data = {
'track_id': vm.selectedTrack.id,
'lease_id': vm.selectedLease.id,
}
// post req to api with lease and track ids
// create payment on server side
fetch('http://localhost:5000/api/paypal/create-purchase', {
method: 'post',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(data),
}).then(function(res) {
return res.json();
}).then(function(data) {
console.log(data.order_id)
return data.order_id
})
}
// conatiner element to render buttons in
}).render('#paypal-button');
And the server side:
#app.route('/api/paypal/create-purchase', methods=['POST'])
def paypal_create_purchase():
# cart validation removed for clarity
# create paypal purchase
environment = SandboxEnvironment(client_id=app.config['PAYPAL_PUBLIC'], client_secret=app.config['PAYPAL_PRIVATE'])
client = PayPalHttpClient(environment)
paypal_request = OrdersCreateRequest()
paypal_request.prefer('return=representation')
paypal_request.request_body (
{
"intent": "CAPTURE",
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": lease.price
}
}
]
}
)
try:
# Call API with your client and get a response for your call
response = client.execute(paypal_request)
order = response.result
print(order.id)
except IOError as ioe:
print (ioe)
if isinstance(ioe, HttpError):
# Something went wrong server-side
print(ioe.status_code)
# note that it is the same key as on the client
return jsonify(success=True,order_id=order.id)
I found this similar thread, but i dont consider the origin of the error to be the same as in that thread (incorrect json key on client)
Also see this relevant page in the docs which supplies this code:
createOrder: function() {
return fetch('/my-server/create-paypal-transaction', {
method: 'post',
headers: {
'content-type': 'application/json'
}
}).then(function(res) {
return res.json();
}).then(function(data) {
return data.orderID; // Use the same key name for order ID on the client and server
});
}
Damn, just as i was typing out the last part of the post i noticed the error. A missing return before my fetch call. Will leave this up for other people with the same mistake.

How to setup greeting text or get_started in JavaScript

I am trying to develop a bot for FB Messenger and I'm always getting stuck with their documentation. Currently, I tried to add a Greeting Text and a Get_Started button in JavaScript, so I will be able to modify it easily. It seems like most of their documentation is in PHP or they just telling you to add it by sending a POST request using CURL, which worked for me, but again, it's not so modular.
I can't find proper documentation in JavaScript. and the only one is this:
https://www.techiediaries.com/build-messenger-bot-nodejs/
But I can't find the place where you actually call the greeting or get started functions.
there is also this https://github.com/fbsamples/original-coast-clothing
but I still can't find where they trigger the Greetings and the Get_Started postbacks. Only the json file where they store it /locales/en_US.json "profile".
My code currently has
// Accepts POST requests at /webhook endpoint
app.post('/webhook', (req, res) => {
// Parse the request body from the POST
let body = req.body;
// Check the webhook event is from a Page subscription
if (body.object === 'page') {
// Iterate over each entry - there may be multiple if batched
body.entry.forEach(function(entry) {
// Get the webhook event. entry.messaging is an array, but
// will only ever contain one event, so we get index 0
let webhook_event = entry.messaging[0];
console.log(webhook_event);
// Get the sender PSID
let sender_psid = webhook_event.sender.id;
console.log('Sender PSID: ' + sender_psid);
// Check if the event is a message or postback and
// pass the event to the appropriate handler function
if (webhook_event.message) {
handleMessage(sender_psid, webhook_event.message);
} else if (webhook_event.postback) {
handlePostback(sender_psid, webhook_event.postback);
}
});
// Return a '200 OK' response to all events
res.status(200).send('EVENT_RECEIVED');
} else {
// Return a '404 Not Found' if event is not from a page subscription
res.sendStatus(404);
}
});
function setupGreetingText(res){
var messageData = {
"greeting":[
{
"locale":"default",
"text":"Greeting text for default local !"
}, {
"locale":"en_US",
"text":"Greeting text for en_US local !"
}
]};
request({
"uri": "https://graph.facebook.com/v2.6/me/messages",
"qs": { "access_token": process.env.PAGE_ACCESS_TOKEN },
"method": 'POST',
"headers": {'Content-Type': 'application/json'},
"form": messageData
},
function (error, response, body) {
if (!error && response.statusCode == 200) {
// Print out the response body
res.send(body);
} else {
// TODO: Handle errors
res.send(body);
}
});
}
but I still dont know how to trigger it.
Examples on the documentation look like this. This is how you break it down. Final result can be found below.
curl -X POST -H "Content-Type: application/json" -d '{
"get_started": {"payload": "<postback_payload>"}
}' "https://graph.facebook.com/v2.6/me/messenger_profile?access_token=<PAGE_ACCESS_TOKEN>"
Third word is the type of request you'll send and should be defined inside the method property.
Between the curly braces, is how the content inside the json property should be formatted.
The link on the last line is the link you should provide to the uri property minus the query part ?access_token=<PAGE_ACCESS_TOKEN>
SendAPI's uri is https://graph.facebook.com/v8.0/me/messages (you're using this)
MessengerProfileAPI's uri is https://graph.facebook.com/v2.6/me/messenger_profile (use this instead)
In the end, your request function should look something like this:
request(
{
"uri": "https://graph.facebook.com/v2.6/me/messenger_profile",
"qs": { "access_token": process.env.PAGE_ACCESS_TOKEN },
"method": "POST",
"json": {
"get_started": {"payload": "start"}
},
},
(err) => {
if (!err) {
console.log('request sent!');
} else {
console.error("Unable to send message:" + err);
}
}
);
Even though its been almost 3 months since this question has been asked. I hope this will still come useful.
Was struggling and frustrated as you trying to implement the examples on facebook for developers documentation but I finally got to understand it after some looking and observation at other developers webhook on github.

Postman pre-request script: Can't access header from response

I am writing the following pre-request Script to get my JWT for authentication:
pm.sendRequest(echoPostRequest, function (err, res) {
console.log(err, res, typeof res);
if(err === null){
console.log(res.header)
// var authHeader = res.header.find(v => {v.key === 'Authorization'})
}
});
This is what the console output currently looks like:
null, {id: "4ba2b741-316e-454d-b896-eab3aef74ae2", status: "OK", code: 200…}, object
undefined
OK
// If you enlarge the opbject it looks like the following:
id: "4ba2b741-316e-454d-b896-eab3aef74ae2"
status: "OK"
code: 200
header: [10] <--- There are my headers ?!
stream: {…}
cookie: [0]
responseTime: 121
responseSize: 0
The problem is I can not access the header array the script always tells me it is undefined, same if I try the access the cookie array. But I can access every other single property, maybe it's because header and cookie are arrays? I don't know. Any ideas what I am doing wrong and how I can get my Authorization header?
I think the Problem must be a bug, my workaround is to stringify and parse the object as json, than the headers are accessible.
r = JSON.parse(JSON.stringify(res))

MongoDB Atlas Trigger -- Receiving a "StitchError: HTTP request failed: unexpected status code: expected=200, actual=415" error

We're trying to create a trigger in MongoDB Atlas that will automatically reduce our Azure tier of an evening to save cost. The function we've put together (probably incorrectly!) returns an error when we try to run it. The result output is:
logs:
uncaught promise rejection: StitchError: HTTP request failed: unexpected status code: expected=200, actual=415
> result:
{
"$undefined": true
}
> result (JavaScript):
EJSON.parse('{"$undefined":true}')
We've tried messing around with the headers and body, but the end result is always the same.
Here's the WIP function:
exports = function() {
const response = context.http.patch({
scheme: "https",
host: "cloud.mongodb.com",
path: "/api/atlas/v1.0/groups/abc123/clusters/fake-server",
username: "usernamehere",
password: "passwordhere",
digestAuth: true,
headers: {"Content-Type": [ "application/json" ]},
body: {"clusterType":"REPLICASET", "providerSettings":{"providerName":"AZURE", "instanceSizeName":"M10", "regionName":"regionhere" } },
encodeBodyAsJSON: true
});
};
Any help would be greatly appreciated.
It turns out that we had it right the whole time.
Executing the exact same code as above is now correctly reducing our tier. I don't know what was causing the MongoDB Atlas API to think that our headers and / or request body were incorrect, but it's perfectly happy with it today.
The only other thing I will point out is that if you want this part of the error to go away...
> result:
{
"$undefined": true
}
> result (JavaScript):
EJSON.parse('{"$undefined":true}')
...you need to change the function to async / await like so:
exports = async function() {
const response = await context.http.patch({

How to Login to MediaWiki (Wikipedia) API in Node.js

I'm trying the Wikipedia client login flow depicted in the API:Login docs, but something wrong happens:
1) I correctly get a token raised with the HTTP GET https://en.wikipedia.org/w/api.php?action=query&meta=tokens&type=login&format=json
and I get a valid logintoken string.
2.1) I then try the clientlogin like:
HTTP POST /w/api.php?action=clientlogin&format=json&lgname=xxxx&lgtoken=xxxx%2B%5C
and the POST BODY was
{
"lgpassword" : "xxxxx",
"lgtoken" : "xxxxx"
}
But I get an error:
{
"error": {
"code": "notoken",
"info": "The \"token\" parameter must be set."
},
"servedby": "mw1228"
}
If I try to change lgtoken to token I get the same result.
2.2) I have then tried the old method i.e. action=login and passing the body, but it does not work, since it gives me back another login token: HTTP POST https://en.wikipedia.org/w/api.php?action=login&format=json&lgname=xxxx
and the same POST BODY
I then get
{
"warnings": {}
},
"login": {
"result": "NeedToken",
"token": "xxxxx+\\"
}
where the docs here states that
NeedToken if the lgtoken parameter was not provided or no session was active (e.g. your cookie handling is broken).
but I have passed the lgtoken in the json body as showed.
I'm using Node.js and the built-in http module, that is supposed to pass and keep session Cookies in the right way (with other api it works ok).
I have found a similar issue on a the LrMediaWiki client here.
[UPDATE]
This is my current implementation:
Wikipedia.prototype.loginUser = function (username, password) {
var self = this;
return new Promise((resolve, reject) => {
var cookies = self.cookies({});
var headers = {
'Cookie': cookies.join(';'),
'Accept': '*/*',
'User-Agent': self.browser.userAgent()
};
// fetch login token
self.api.RequestGetP('/w/api.php', headers, {
action: 'query',
meta: 'tokens',
type: 'login',
format: 'json'
})
.then(response => { // success
if (response.query && response.query.tokens && response.query.tokens['logintoken']) {
self.login.logintoken = response.query.tokens['logintoken'];
self.logger.info("Wikipedia.login token:%s", self.login);
return self.api.RequestPostP('/w/api.php', headers, {
action: 'login',
format: 'json',
lgname: username
},
{
lgpassword: password,
lgtoken: self.login.logintoken
});
} else {
var error = new Error('no logintoken');
return reject(error);
}
})
.then(response => { // success
return resolve(response);
})
.catch(error => { // error
self.logger.error("Wikipedia.login error%s\n%#", error.message, error.stack);
return reject(error);
});
});
}//loginUser
where this.api is a simple wrapper of the Node.js http, the source code is available here and the api signatures are like:
Promise:API.RequestGetP(url,headers,querystring)
Promise:API.RequestPostP(url,headers,querystring,body)
If the currently accepted answer isn't working for someone, the following method will definitely work. I've used the axios library to send requests. Any library can be used but the key lies in formatting the body and headers correctly.
let url = "https://test.wikipedia.org/w/api.php";
let params = {
action: "query",
meta: "tokens",
type: "login",
format: "json"
};
axios.get(url, { params: params }).then(resp => {
let loginToken = resp.data.query.tokens.logintoken
let cookie = resp.headers["set-cookie"].join(';');
let body = {
action: 'login',
lgname: 'user_name',
lgpassword: 'password',
lgtoken: loginToken,
format: 'json'
}
let bodyData = new URLSearchParams(body).toString();
axios.post(url, bodyData, {
headers: {
Cookie: cookie,
}
}).then(resp => {
// You're now logged in!
// You'll have to add the following cookie in the headers again for any further requests that you might make
let cookie = resp.headers["set-cookie"].join(';')
console.log(resp.data)
})
})
And you should be seeing a response like
{
login: { result: 'Success', lguserid: 0000000, lgusername: 'Username' }
}
The second post request was where I got stuck for several hours, trying to figure out what was wrong. You need to send the data in an encoded form by using an API like URLSearchParams, or by just typing up the body as a string manually yourself.
I think from what you are saying you have lgtoken and lgname in the URL you are using, and then lgpassword and lgtoken (again!) in a JSON-encoded POST body.
This is not how the Mediawiki API works.
You submit it all as POST parameters. JSON is never involved, except when you ask for the result to come back in that format. I can't help you fix your code as you don't provide it, but that's what you need to do. (If you edit your question with your code, I'll do my best to help you.)
After seeing your code, I'll presume (without knowing the detail of your code) that you want something like this:
return self.api.RequestPostP('/w/api.php', headers, {
action: 'login',
format: 'json',
lgname: username,
lgpassword: password,
lgtoken: self.login.logintoken
});

Categories