JS require in QML - javascript

I am using the dbox library in a QML app (sources available at github). In a QML file I import the dbox library with the following code:
import "./dbox-master/lib/dbox.js" as Dbox
Then I use it in this way:
var app = Dbox.app({ "app_key": root.appKey, "app_secret": root.appSecret })
However, in the dbox.js there're series of require statements, at the top of the file:
define(['require', 'request', 'querystring', 'path'], function (require) {
var request = require('request');
var qs = require('querystring');
var path = require('path');
var helpers_ = require("./helpers")
// var request = require('request');
});
//var request = require("request")
//var qs = require("querystring")
//var path = require("path")
//require(['request'], function (foo) {
// console.log('request is loaded')
//});
exports.app = function(config){
var root = config.root || "sandbox"
var helpers = helpers_(config)
return {
root: root,
requesttoken: function(cb){
var signature = helpers.sign({})
var body = qs.stringify(signature)
var args = {
"method": "POST",
"headers": {
"content-type": "application/x-www-form-urlencoded",
"content-length": body.length
},
"url": "https://api.dropbox.com/1/oauth/request_token",
"body": body
}
return request(args, function(e, r, b){
var obj = qs.parse(b)
obj.authorize_url = "https://www.dropbox.com/1/oauth/authorize?oauth_token=" + obj.oauth_token
cb(e ? null : r.statusCode, obj)
})
},...
As you see, I've changed the code to get the dbox.js to work but the require is not defined. How to use the require.js properly?
Update.
As I found out, the problem is in the host environment. The QML global space is constant. Node.js requires objects to be present in the space (e.g. iself) and importing into the global space. There is a project on github glueing Node.js and QML but it is not finished yet. I propose another solution: make a C++ plugin to run a script in js. The script is run in the Node.js environment to communicate Dropbox account information to the Quick-based application.

What is the best approach to use a web API? Dropbox in this case.
It depends.
Since I need to list all files and download a file, the best choice is to use the Dropbox API manually.
I used OAuth2 to authorize the application, the Token Flaw, because it is fast.
WebView was the app. built-in browser. Once a redirect_uri is set as the WebView url property value then it means the authorization is passed. The access token is returned with the redirection.
Note.
The redirect_uri must be equal to the redirect_uri set in the application AppConsole in the app. Dropbox account.
Result: I did not use the 3d party Dropbox JS libraries, it is much faster to send requests manually.

Related

how to: wsse soap request in javascript (node)

I need to communicate with a soap:xml API from a node server on the Wix.com platform. The API requires Soap WSSE authentication.
I can send an authenticated request to the endpoint in SoapUI, however haven't been able successfully do this on the Wix node platform.
Wix only have a subset of node packages available for install and XMLHttpRequest is not available in their environment.
I have tried node-soap but receive errors which indicate the package might be buggy on the Wix node platform.
I've found myself using the node "request" (https://www.npmjs.com/package/request) package and trying to roll my own solution to work around missing node packages and environment restrictions.
Currently I can send a request to the end point however I receive the following response;
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Client</faultcode><faultstring>Access denied</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>\n
This suggests to me i'm not authenticating correctly.
As I mentioned, I've been able to successfully send requests and receive expected responses via SoapUI. So the API is functioning, and I suspect it's my implementation that is at fault. I'll be honest, I've worked with REST/JSON API's in the past, and it has been a long time since i've worked with a SOAP API, and I remember even back then having a whole lot of pain!
my request code
import request from 'request';
import {wsseHeaderAssoc} from 'backend/wsse';
export function getLocationID() {
let apiUsername = "username";
let apiPassword = "password";
let apiURL = "https://api.serviceprovider.com/wsdl";
// WSSE authentication header vars
    let wsse = wsseHeaderAssoc(apiUsername, apiPassword);
let wsseUsername = wsse["Username"];
let wssePasswordDigest = wsse["PasswordDigest"];
let wsseCreated = wsse["Created"];
let wsseNonce = wsse["Nonce"];
let xml =
`<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:masked:api">`+
`<soapenv:Header>`+
`<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">`+
`<wsse:UsernameToken wsu:Id="UsernameToken-19834957983507345987345987345">`+
`<wsse:Username>${wsseUsername}</wsse:Username>`+
`<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">${wssePasswordDigest}</wsse:Password>`+
`<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">${wsseNonce}</wsse:Nonce>`+
`<wsu:Created>${wsseCreated}</wsu:Created>`+
`</wsse:UsernameToken>`+
`</wsse:Security>`+
`</soapenv:Header>`+
`<soapenv:Body>`+
...
`</soapenv:Body>`+
`</soapenv:Envelope>`
var options = {
url: apiURL,
method: 'POST',
body: xml,
headers: {
'Content-Type':'text/xml;charset=utf-8',
'Accept-Encoding': 'gzip,deflate',
'Content-Length':xml.length,
'SOAPAction':"https://api.serviceprovider.com/wsdl/service",
'User-Agent':"Apache-HttpClient/4.1.1 (java 1.5)",
'Connection':"Keep-Alive"
}
};
let callback = (error, response, body) => {
if (!error && response.statusCode == 200) {
console.log('Raw result ', response);
// If you ever get this working, do some mad magic here
};
console.log('Error ', response);
};
}
I'm using wsse-js (https://github.com/vrruiz/wsse-js/blob/master/wsse.js) to generate the PasswordDigest, Created datetime stamp and Nonce as the node wsse package (https://www.npmjs.com/package/wsse) isn't available on Wix. I've read over the code and based on what i've read elsewhere this looks like a good implementation.
I made one small addition to return the generated details in an assoc array;
export function wsseHeaderAssoc(Username, Password) {
var w = wsse(Password);
var wsseAssoc = [];
wsseAssoc["Username"] = Username;
wsseAssoc["PasswordDigest"] = w[2];
wsseAssoc["Created"] = w[1];
wsseAssoc["Nonce"] = w[0];
return wsseAssoc;
}
As stated earlier i'm receiving a response of;
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Body><SOAP-ENV:Fault><faultcode>SOAP-ENV:Client</faultcode><faultstring>Access denied</faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>\n
And i'm expecting a valid SOAP XML response.
I've used the raw xml structure and headers from SoapUI to construct this, everything looks fine, i really have no idea where i'm going wrong.
I would love any pointers anyone could throw my way - I've lost 2 days trying to brute force this, I need help.
You can use the WSSecurity method from the soap package. An example from their README:
var options = {
hasNonce: true,
actor: 'actor'
};
var wsSecurity = new soap.WSSecurity('username', 'password', options)
client.setSecurity(wsSecurity);

Upload large files as a stream to s3 with Plain Javascript using AWS-SDK-JS

There is a pretty nice example available for uploading large files to s3 via aws-sdk-js library but unfortunately this is using nodeJs fs.
Is there a way we can achieve the same thing in Plain Javascript? Here is a nice Gist as well which breaks down the large file into the smaller Chunks however this is still missing the .pipe functionality of nodeJs fs which is required to pass to asw-sdk-js upload function. Here is a relevant code snippet as well in Node.
var fs = require('fs');
var zlib = require('zlib');
var body = fs.createReadStream('bigfile').pipe(zlib.createGzip());
var s3obj = new AWS.S3({params: {Bucket: 'myBucket', Key: 'myKey'}});
s3obj.upload({Body: body}).
on('httpUploadProgress', function(evt) {
console.log('Progress:', evt.loaded, '/', evt.total);
}).
send(function(err, data) { console.log(err, data) });
Is there something similar available in Plain JS (non nodeJs)? Useable with Rails.
Specifically, an alternative to the following line in Plain JS.
var body = fs.createReadStream('bigfile').pipe(zlib.createGzip());
The same link you provided contains an implementation intended for the Browser, and it also uses the AWS client SDK.
// Get our File object
var file = $('#file-chooser')[0].files[0];
// Upload the File
var bucket = new AWS.S3({params: {Bucket: 'myBucket'});
var params = {Key: file.name, ContentType: file.type, Body: file};
bucket.upload(params, function (err, data) {
$('#results').html(err ? 'ERROR!' : 'UPLOADED.');
});
** EDITS **
Note the documentation for the Body field includes Blob, which means streaming will occur:
Body — (Buffer, Typed Array, Blob, String, ReadableStream)
You can also use the Event Emitter convention in the client offered by the AWS SDK's ManagedUpload interface if you care to monitor progress. Here is an example:
var managed = bucket.upload(params)
managed.on('httpUploadProgress', function (bytes) {
console.log('progress', bytes.total)
})
managed.send(function (err, data) {
$('#results').html(err ? 'ERROR!' : 'UPLOADED.');
})
If you want to read the file from your local system in chunks before you send to s3.uploadPart, you'll want to do something with Blob.slice, perhaps defining a Pipe Chain.

how to use Cryptocapital API v4, can't find sdk download link

Cryptocapital.co provides API to exchange crypto currency, I want to access their API to integrate with a website, they do have a documentation here - https://api.cryptocapital.co/v4
and they have a sample code as below
var key = '1234567890abcdef';
var secret = '1234567890abcdef';
var command = 'PING';
var nonce = Date.now();
var message = command + nonce;
var signature = CryptoJS.SHA1(message + key + secret);
var options = {
url: 'https://api.cryptocapital.co/v4/ping',
headers: {
'key': key,
'message': message,
'signature': signature,
'nonce': nonce
}
};
request(options, function(err, res, body) {
// do something
// ...
});
There is no download link or reference to any SDK, when i run this code it says
request is not defined
I don't know where to start in this specific API.
please see the documentation and help me on identifying what I am doing wrong.
It's making the assumption that your using the popular request lib to make the HTTP request.
You can, however, use whatever library you like. Or don't use a library at all, use https.get.

Accessing Google Drive from a Firefox extension

I'm trying to access (CRUD) Google Drive from a Firefox extension. Extensions are coded in Javascript, but neither of the two existing javascript SDKs seem to fit; the client-side SDK expects "window" to be available, which isn't the case in extensions, and the server-side SDK seems to rely on Node-specific facilities, as a script that works in node no longer does when I load it in chrome after running it through browserify. Am I stuck using raw REST calls? The Node script that works looks like this:
var google = require('googleapis');
var readlineSync = require('readline-sync');
var CLIENT_ID = '....',
CLIENT_SECRET = '....',
REDIRECT_URL = 'urn:ietf:wg:oauth:2.0:oob',
SCOPE = 'https://www.googleapis.com/auth/drive.file';
var oauth2Client = new google.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL);
var url = oauth2Client.generateAuthUrl({
access_type: 'offline', // 'online' (default) or 'offline' (gets refresh_token)
scope: SCOPE // If you only need one scope you can pass it as string
});
var code = readlineSync.question('Auth code? :');
oauth2Client.getToken(code, function(err, tokens) {
console.log('authenticated?');
// Now tokens contains an access_token and an optional refresh_token. Save them.
if(!err) {
console.log('authenticated');
oauth2Client.setCredentials(tokens);
} else {
console.log('not authenticated');
}
});
I wrap the node GDrive SDK using browserify on this script:
var Google = new function(){
this.api = require('googleapis');
this.clientID = '....';
this.clientSecret = '....';
this.redirectURL = 'urn:ietf:wg:oauth:2.0:oob';
this.scope = 'https://www.googleapis.com/auth/drive.file';
this.client = new this.api.auth.OAuth2(this.clientID, this.clientSecret, this.redirectURL);
}
}
which is then called using after clicking a button (if the text field has no code it launches the browser to get one):
function authorize() {
var code = document.getElementById("code").value.trim();
if (code === '') {
var url = Google.client.generateAuthUrl({access_type: 'offline', scope: Google.scope});
var win = Components.classes['#mozilla.org/appshell/window-mediator;1'].getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow('navigator:browser');
win.gBrowser.selectedTab = win.gBrowser.addTab(url);
} else {
Google.client.getToken(code, function(err, tokens) {
if(!err) {
Google.client.setCredentials(tokens);
// store token
alert('Succesfully authorized');
} else {
alert('Not authorized: ' + err); // always ends here
}
});
}
}
But this yields the error Not authorized: Invalid protocol: https:
It is possible though, depending on the use case, it might also of limited interest.
Firefox ships with a tiny http server, just the bare bones. It is included for test purposes but this is not a reason to overlook it.
Lets follow the quickstart guide for running a Drive app in Javascript
The tricky part is to set the Redirect URIs and the Javascript Origins. Obviously the right setting is http://localhost, but how can you be sure that every user has port 80 available?
You can't and, unless you have control over your users, no port is guaranteed to work for everyone. With this in mind lets choose port 49870 and pray.
So now Redirect URIs and the Javascript Origins are set to http://localhost:49870
Assuming you use Add-on SDK, save the quickstart.html (remember to add your Client ID) in the data directory of your extension. Now edit your main.js
const self = require("sdk/self");
const { Cc, Ci } = require("chrome");
const tabs = require("sdk/tabs");
const httpd = require("sdk/test/httpd");
var quickstart = self.data.load("quickstart.html");
var srv = new httpd.nsHttpServer();
srv.registerPathHandler("/gdrive", function handler(request, response){
response.setHeader("Content-Type", "text/html; charset=utf-8", false);
let converter = Cc["#mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
response.write(converter.ConvertFromUnicode(quickstart));
})
srv.start(49870);
tabs.open("http://localhost:49870/gdrive");
exports.onUnload = function (reason) {
srv.stop(function(){});
};
Notice that quickstart.html is not opened as a local file, with a resource: URI. The Drive API wouldn't like that. It is served at the url http://localhost:49870/gdrive. Needless to say that instead of static html we can use a template or anything else. Also the http://localhost:49870/gdrive can be scripted with a regular PageMod.
I don't consider this a real solution. It's just better than nothing.
From here https://developer.mozilla.org/en/docs/Working_with_windows_in_chrome_code you could try window = window || content || {}
Use the JavaScript client API and not the node.js client. Although browserify will make it work. You will have to expose your client secret in the latter. The flow of client side authentication is very diff than server side. Refer to https://developers.google.com/accounts/docs/OAuth2
Having said all this. Its really not that difficult to implement an app with REST based calls. The methods in all client libraries mimic the corresponding REST URLs. You could set up some functions of your own to handle request and response and the rest would feel the same.

Phonegap PushNotification, how to use my node push-server with phonegap?

So, i'm on Phonegap, i use :
https://github.com/phonegap-build/PushPlugin/
https://github.com/argon/node-apn
So, i install the first plugin and i can get my phone token. After that, i created a node server.js file in my root directory with :
var apn = require('apn');
var token = "MY TOKEN";
var device = new apn.Device(token);
var notification = new apn.Notification();
notification.expiry = Math.floor(Date.now() / 1000) + 3600;
notification.badge = 1;
notification.alert = "This is a Push Notification=)";
notification.payload = {'prop': 'special value'};
notification.device = device;
var options = {
gateway: 'gateway.sandbox.push.apple.com',
cert: 'CER.pem',
key: 'KEY.pem',
passphrase: 'password'
}
var apnsConnection = new apn.Connection(options);
apnsConnection.pushNotification(notification, device);
When i start my server with node server.js in command line, i can see my push notification on my phone, so all it's ok.
But my question, i need to send push notification in different place in my code (phonegap). How can i do that ?
When my server.js is running, how can i send other push notification from my phonegap application ?
What you have above is code that you can collect together, and expose a function to call it multiple times. For example, a very simple implementation would be:
var apn = require('apn');
var options = {
gateway: 'gateway.sandbox.push.apple.com',
cert: 'CER.pem',
key: 'KEY.pem',
passphrase: 'password'
};
var apnsConnection = new apn.Connection(options);
module.exports.pushNotification = function(token, alert) {
var device = new apn.Device(token);
var notification = new apn.Notification();
notification.alert = alert;
notification.device = device;
apnsConnection.pushNotification(notification, device);
};
Imagine you name this file pns.js for "push notification service". Now in your server.js, you could instead require that module you just created and call the pushNotification function:
var pns = require("./pns.js");
pns.pushNotification("MY TOKEN", "This is a Push Notification");
Now you've got the same function when you execute the server.js. From here, you could instead pull this function into other modules that need to call it from the Node.js side of things.
If you need to call it from a remote process, you could look into a web framework like Express, and build an API which calls the same code. The token and alert message could then be passed in to this function call. Doing this would likely turn your server.js into a running web server which listens for requests and sends push notifications on demand.
A bit late, but for people with the same question, look at this tool:
https://www.npmjs.com/package/node-pushserver
...it does exactly what you want. It supports both iOS and Android.
Run this on a server and your app can: register the device by POSTing to http://yourserver:8000:/subscribe. Devices are stored in a mongodb database. By POSTing a http request to http://yourserver:8000/send, you can send push notifications to a single registered device, a subset or all of them.
Have fun!

Categories

Resources