What i'd like to achieve is to dynamically create hosted PayPal buttons through the Button Manager API offered by PayPal, preferrably the NVP API. I would like to do so using client side Javascript.
Surprisingly, after extensive searching online I've failed to find a sample of code that achieves that goal.
Reading into the PayPal documentation led me to believe that I can use the API with xmlhttprequests. However, I fail to get a reply from PayPal. I've created a string with some arbitrary parameters which should be correct, and come as far as:
var xmlhttp;
function generateButton()
{
console.log("Function begun") ;
var strUrl= "https://api.paypal.com/nvp";
var strParameters="?METHOD=BMCreateButton&VERSION=204.0&BUTTONCODE=HOSTED&BUTTONTYPE=BUYNOW&BUTTONSUBTYPE=PRODUCTS&L_BUTTONVAR0=amount=15.00&L_BUTTONVAR1=item_name=test_item2USER=***&PWD=***&SIGNATURE=***";
var urlRequest= strUrl+encodeURI(strParameters);
if (window.XMLHttpRequest)
{
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else if (window.ActiveXObject)
{
// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
alert("Your browser does not support XMLHTTP!");
}
xmlhttp.open("POST",urlRequest,true);
xmlhttp.onreadystatechange= function(){
alert(xmlhttp.statusText) ;
if (xmlhttp.readyState==4)
{
alert(xmlhttp.responseText) ;
}
};
xmlhttp.send();
}
My paypal credentials are listed as *** for privacy purposes, and in my code they are proper. Am I going about this the right way? Are my parameters incorrect, or is the issue with my xmlhttprequest? Bear in mind that I am new to web programming, and detailed explanations would be appreciated.
Thank you.
After some further reading, it seems calling the Button Manager API through client side javascript is not a correct approach as it requires a cross domain request (which browsers do not allow for security reasons).
It is possible to bypass this restriction with the CORS mechanism, but as far as I can tell PayPal does not support it. Other solutions exist but are 'dirty'.
I've concluded that it is better to make the request through a server. Requests can be made to your own server, which would invoke the button manager API and forward the reply (your new button's HTML code) back to the client.
Here is a NodeJS program code to create a new hosted button, which you can implement in your server:
var querystring = require('querystring'); // to URL encode for the NVP
var https = require('https'); // to use the NVP API, request must be https
// Prototype for a create button request fields, you can get your input from database, client side user or just hard code it
function CreateButtonRequest(user, pwd, signature, buttonPrice, buttonName){
this.USER =user,
this.PWD = pwd,
this.SIGNATURE = signature,
this.METHOD = "BMCreateButton",
this.VERSION = "204.0",
this.BUTTONCODE = "HOSTED",
this. BUTTONTYPE = "BUYNOW",
this.BUTTONSUBTYPE = "PRODUCTS",
this.L_BUTTONVAR0 = "amount="+buttonPrice,
this.L_BUTTONVAR1 = "item_name="+buttonName
}
// A sample request
// Replace **** with your API certificate specifics, find them in your paypal account
sampleRequestData = {
USER : "****",
PWD : "****",
SIGNATURE : "****",
METHOD : "BMCreateButton",
VERSION : "204.0",
BUTTONCODE : "HOSTED",
BUTTONTYPE : "BUYNOW",
BUTTONSUBTYPE : "PRODUCTS",
L_BUTTONVAR0 : "amount=10.00",
L_BUTTONVAR1 : "item_name=test item2"
};
sampleRequestData = querystring.stringify(postData);
//init your options object after you call querystring.stringify because you need
// the return string for the 'content length' header
console.log(sampleRequestData) ;
var options = {
host: 'api-3t.paypal.com',
port: 443,
method: 'POST',
path: '/nvp',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postBody.length
}
};
var postreq = https.request(options, function (res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('Response: ' + chunk);
});
});
postreq.write(sampleRequestData);
postreq.end();
console.log("Message sent...") ;
Related
I want to change python to apps script in apps script have UrlFetchApp function i'm never use but i'm try
I have code python can get api normally
import requests
url = "https://api.aiforthai.in.th/ssense"
text = 'Have a good day'
params = {'text':text}
headers = {
'Apikey': "xxx-xxx-xxx"
}
response = requests.get(url, headers=headers, params=params)
print(response.json())
so now i'm try code apps script like this but notthing came out ;
Api dashboard call me i'm use api.
maybe wrong payload text?
Detail API
Host
https://api.aiforthai.in.th/ssense
Method
GET/POST
Header
Apikey : xxx-xxx-xxx
Content-Type : application/x-www-form-urlencoded
Parameter
text : text for analysis
This my wrong apps script code
function call_api() {
var url = "https://api.aiforthai.in.th/ssense"
var apiKey = "xxx-xxx-xxx";
var response = UrlFetchApp.fetch(
url,
{
"headers": {
"Apikey": apiKey,
"text": "Have a good day"
}
}
)
Logger.log(response)
}
Thank you for solution.
I believe your goal is as follows.
You want to convert the following python script to Google Apps Script.
import requests
url = "https://api.aiforthai.in.th/ssense"
text = 'Have a good day'
params = {'text':text}
headers = {
'Apikey': "xxx-xxx-xxx"
}
response = requests.get(url, headers=headers, params=params)
print(response.json())
You have already been confirmed that your python script worked fine.
When I saw your python script, text is sent as the query parameter. In this case, how about the folloiwng modification?
Modified script:
function call_api2() {
var text = "Have a good day";
var url = `https://api.aiforthai.in.th/ssense?text=${encodeURIComponent(text)}`;
var apiKey = "xxx-xxx-xxx";
var response = UrlFetchApp.fetch(
url,
{ "headers": { "Apikey": apiKey } }
);
Logger.log(response.getContentText());
}
Note:
If you test the above modified script, when an error occurs, please confirm your apiKey again.
If an error like status code 403 occurs, your URL might not be able to be requested from Google side. I'm worried about this.
Try this instead:
function call_api() {
var url = "https://api.aiforthai.in.th/ssense";
var apiKey = "xxx-xxx-xxx";
var response = UrlFetchApp.fetch(
url,
{
"method" : "GET",
"headers" : {
"Apikey" : apiKey,
"text" : "Have a good day"
}
}
);
Logger.log(response)
}
You can check out the UrlFetchApp documentation for future reference.
I would like to make a Basic HTTP authentication call request via javascript but I do not know how to do it.. I have a javascript code and inside of it there is a session parameter. Thus, I need to make first this call, get the session_id from this call as a response and continue my javascript code. This is the doc of this basic http auth: https://ibanke-commerce.nbg.gr/api/documentation/apiDocumentation/rest-json/version/latest/operation/Session%3a%20Create%20Checkout%20Session.html?locale=en_US
It is about payment option between bank and ecommerce.
How will this be written in javascript?
My code structure is like this for now:
<script
//need call auth somewhere here I guess
Payment.Config({
... ... ..
Url: "...",
Name: "...",
session: "here I need the response of the call"
...
...
});
</script>
Any help/guidelines would be appreciated
You need three things:
1. Create you Basic Header for your authentication
The Basic Header is an Base64 encoded string of your user and
password. To get that you should encode your credentials as shown below.
user_id:password
In you case user_id is the merchantId
You can use online services like this to encode your credentials strings
Or
You can encode it in your javascript code like this
var clientId = "user_id";
var clientSecret = "password";
// var authorizationBasic = $.base64.btoa(clientId + ':' + clientSecret); // jQuery
var authorizationBasic = window.btoa(clientId + ':' + clientSecret); // Javascript
I would recommend the first option.
2. Make your post request with the Basic Header
You can follow this answer on how to make an HTTP POST authentication basic request using Javascript
3. Use the response from the authentication request in your code
So your final code would be something like this
var url = 'your_url_server';
var authorizationBasic = 'the_created_basic_header';
var request = new XMLHttpRequest();
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.setRequestHeader('Authorization', 'Basic ' + authorizationBasic);
request.setRequestHeader('Accept', 'application/json'); // Modify according to the response format
request.send("parameter1=parameter1_value¶meter2=parameter2_value"); // Any parameter you might need
request.onreadystatechange = function () {
if (request.readyState === 4) {
alert(request.responseText);
Payment.Config({
... ... ..
Url: "...",
Name: "...",
session: request.responseText // Here is the response of the call
...
...
});
}
};
If we use javascript's http request function:
var request = new XMLHttpRequest();
to an https address, will this use any type of encryption or will a MITM be able to see all data we send?
Example:
function createAuthToken(baseRestURL, callback) {
var APIPath = "account/api/session";
var CORSPath = "https://cors-anywhere.herokuapp.com/";
var completeRestURL = CORSPath + baseRestURL + APIPath;
console.log("REST API URL: " + completeRestURL);
var method = "POST";
var postData = "{\"tokenId\": \"" + document.getElementById('api_key').value + "\",\"secret\": \"" + document.getElementById('secret').value + "\",\"loginMode\": 1,\"applicationType\": 35}";
var async = true;
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState == 4 && (request.status == 200 || request.status == 201)) {
console.log("ONLOAD");
var status = request.status; // HTTP response status, e.g., 200 for "200 OK"
console.log(status);
var response = JSON.parse(request.responseText);
console.log(response.session_token);
return callback(response.session_token);
}
}
request.open(method, completRestURL, async);
request.setRequestHeader("Content-Type", "application/json");
request.setRequestHeader("Accept", "application/json");
request.send(postData);
Follow up question: If not, is there a way to include encryption in our client side javascript that is safe? My thoughts was to use a webisite's public key to encrypt the request before sending it to the server but I can't find anyone else attempting client side encryption.
Rough example:
var CryptoJS = require("crypto-js");
var stackOverflowKey = "30 82 01 0a 02 82 01..."
var postData = "{\"tokenId\": \"" + document.getElementById('api_key').value + "\",\"secret\": \"" + document.getElementById('secret').value + "\",\"loginMode\": 1,\"applicationType\": 35}";
var encryptedPostData = cryptoJS.hmacSHA256(postData, stackOverflowKey)
//let's skip the callback and request headers as they are the same as above
var request = new XMLHttpRequest();
request.open();
request.send(encryptedPostData);
I didn't study computer science and couldn't find anything online about this. What are the generally accepted ways of doing this?
The HTTP in XMLHttpRequest, as is the XML part, is just a left over naming scheme. As the requests used can include more than just http protocol urls, and receive more than just an XML response body.
For instance the initial W3C working drafts introduced the XMLHttpRequest object by saying:
https://www.w3.org/TR/2006/WD-XMLHttpRequest-20060927/#introduction
The name of the object is XMLHttpRequest for compatibility with the web
as it doesn't make much sense otherwise. It supports the transport of
other data formats in addition to XML, some implementations support
other protocols besides HTTP (that functionality is not covered in
this specification though) and the API supports sending data as well.
Note the "some implementations" as this is a working draft back in 2006 so not everyone was using the same implementation.
The current whatwg spec for XMLHttpRequest has this to say about the name:
https://xhr.spec.whatwg.org/#introduction
The name XMLHttpRequest is historical and has no bearing on its
functionality.
So as long as the browser being used implements the XMLHttpRequest according to specs, the request/response will be treated as it would normally by the browser, ie encrypted for https.
I am using Titanium (Appcelerator) to connect to Fitbit API. (http://www.appcelerator.com)
I have been facing issues of getting "Invalid Signature" when I am trying to request for token.
I'm using HTTPClient from Titanium.Network.HTTPClient class to send the HTTP Request.
I also uses the oauth-1.0a.js library from https://github.com/ddo/oauth-1.0a to assist in getting the nonce and signature value.
Here is the code:
Ti.include('/oauth/ddo/hmac-sha1.js');
Ti.include('/oauth/ddo/enc-base64-min.js');
Ti.include('/oauth/ddo/oauth-1.0a.js');
function FitBitAuth() {
FitBitAuth.signatureMethod = "HMAC-SHA1";
FitBitAuth.clientKey = 'XXXXXXXXXXXXXXXXXXXXXXXXX';
FitBitAuth.clientSecret = 'XXXXXXXXXXXXXXXXXXXXXXXXXX';
FitBitAuth.nonce = "R#nD0m_$tR!nGss";
FitBitAuth.request_token_url = "https://api.fitbit.com/oauth/request_token";
FitBitAuth.callback_url = "http://www.fitbit.com";
}
FitBitAuth.prototype.createConsumerTokenSecretPair = function() {
return OAuth({
consumer : {
public : FitBitAuth.clientKey,
secret : FitBitAuth.clientSecret
},
signature_method : FitBitAuth.signatureMethod
});
};
FitBitAuth.prototype.getRequestTokenRequestData = function() {
return {
url : "https://api.fitbit.com/oauth/request_token",
method : 'POST'
};
};
FitBitAuth.prototype.requestToken = function() {
var oauth = this.createConsumerTokenSecretPair();
var request_data = this.getRequestTokenRequestData();
var authorized_request = oauth.authorize(request_data, '', FitBitAuth.nonce, FitBitAuth.timestamp);
//alert(authorized_request);
return authorized_request;
};
function auth1a() {
var fb = new FitBitAuth();
var rt = fb.requestToken();
var req = Ti.Network.createHTTPClient();
req.open("POST", FitBitAuth.request_token_url);
req.setRequestHeader('Authorization', 'OAuth oauth_consumer_key="'+FitBitAuth.clientKey+'"');
Ti.API.info(rt);
req.send({
oauth_timestamp : rt.oauth_timestamp,
oauth_nonce : rt.oauth_nonce,
oauth_signature : encodeURIComponent(rt.oauth_signature),
oauth_signature_method: rt.oauth_signature_method,
oauth_callback : encodeURIComponent(FitBitAuth.callback_url),
oauth_version : rt.oauth_version
});
req.onload = function() {
var json = this.responseText;
Ti.API.info("HEADER =====================");
Ti.API.info(req.getAllResponseHeaders());
Ti.API.info("END HEADER =================");
Ti.API.info(json);
var response = JSON.parse(json);
//alert(response);
};
}
I have also tried the Fitbit API Debug tool to assist me in getting all the signature right, in fact the signature and base String do match with the one shown by Fitbit API Debug Tool.
However, I keep getting this Invalid Signature, a sample JSON return is shown below:
{"errors":[{"errorType":"oauth","fieldName":"oauth_signature","message":"Invalid signature: rN**ahem**SGJmFwHp6C38%2F3rMKEe6ZM%3D"}],"success":false}
I have also already tested to do the curl way and it works from Terminal, but to no avail it does not give me a success from Titanium.
Any help is appreciated.
I manage to solve it.
I tried to use another way of inserting the parameters through the header.
Such that the setRequestHeader will look like this:
req.setRequestHeader('Authorization', 'OAuth oauth_consumer_key="'+FitBitAuth.clientKey+'", oauth_nonce="'+rt.oauth_nonce+'", oauth_signature="'+rt.oauth_signature+'",...');
Alternatively, we can also use the built in toHeader feature of the oauth library that I'm using:
oauth.toHeader(oauth_data);
The code above will produce the oauth data in key-value pair.
{
'Authorization' : 'OAuth oauth_consumer_key="xxxxxxxxxxxxx"&oauth_nonce="xxxxxx"&...
}
So instead of the long code for setRequestHeader, we can make use of the value of toHeader, code shown below:
req.setRequestHeader('Authorization', oauth.toHeader(oauth_data).Authorization);
Do note that the return result by fitbit is in plaintext.
auth_token=xxxxxxxx&auth_token_secret=xxxxxxxxx&...
I am trying to call a Hessian web service from a Javascript application, but I'm having issues parsing the response, since jQuery is treating the response as text and stripping the first bytes of it.
In my research, I have found out that you need to set the charset as 'charset=x-user-defined' in order to the browser leave my bytes as is. But, according the ajax docs:
Sending Data to the Server
By default, Ajax requests are sent using the GET HTTP method. If the
POST method is required, the method can be specified by setting a
value for the type option. This option affects how the contents of the
data option are sent to the server. POST data will always be
transmitted to the server using UTF-8 charset, per the W3C
XMLHTTPRequest standard.
And indeed, the charset is not changing regardless of the settings I used. I have tried the following, separately and all at once, with no luck
$.ajax({
type : 'POST',
url : url,
timeout : 3000,
data : parameters,
contentType : "x-application/hessian; charset=x-user-defined'",
mimeType: 'text/plain; charset=x-user-defined',
headers: {
Accept : "text/plain; charset=x-user-defined",
"Content-Type": "text/plain; charset=x-user-defined"
},
beforeSend : function(xhr) {
xhr.overrideMimeType("text/plain; charset=x-user-defined");
}
})
Also I tried to mess around with the data converters and custom contenttypes defined in jQuery, with no succes.
It appears that as per the standard, I will not be able to do this. It works with GET but not with POST, and the Hessian protocol requires POST.
Do you have any ideas? Or do I need to start to build my XHR method form scratch?
Turns out that I was making a silly mistake somewhere else. But anyhow, I found a sweet way for handling binary data on request and responses, from here.
define(function() {
// Do setup work here
function configurationException(message) {
throw new Error(message + " missing from configuration object");
}
return {
post : function(config) {
if (config) {
var url = config.url || configurationException("url");
var done = config.done || configurationException("callback function");
var timeout = config.timeout || 10000;
var data;
if (config.data) {
data = config.data;
} else {
data = null;
console.warn('No data is specified in binaryPost');
}
var request = new XMLHttpRequest();
request.open("POST", url, true);
request.responseType = "arraybuffer";
request.setRequestHeader("Content-Type", "x-application/hessian;");
request.onload = function(oEvent) {
var arrayBuffer = request.response; // Note: not oReq.responseText
if (arrayBuffer) {
var byteArray = new Uint8Array(arrayBuffer);
done(byteArray);
}
};
request.send(data);
} else {
throw new Error("Configuration object is missing");
}
}
};
});
Hope you find it useful