xmlHttpRequest to absolute url in WP8 - windows-phone-8

I have stumbled across an odd issue when testing an app in Windows Phone 8. I am using xmlHttpRequest (cannot use ajax as I need to send as bufferarray) to make a call to a third party url. This works perfectly in Android and iOS, but throws an error in WP8
Example:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function (){
if(xhr.readyState == 4){
if(xhr.status==200){
alert(xhr.responseText);
}else{
console.log("Error: "+xhr.responseText);
}
}
}
console.log("1");
xhr.timeout = 30000;
console.log("2");
xhr.open("POST","http://google.com",true);
console.log("3");
xhr.setRequestHeader("Content-Type",contentType+"; boundary=" + boundary);
console.log("4");
//other headers / auth etc
console.log("about to post");
xhr.send(bodyBuf);
this will result in:
log:"before request"
log:"1"
log:"2"
log:"Error in error callback: Cameraxxxxx = InvalidStateError"
However if I chang the open to:
xhr.open("POST","google.com",true); //or www.google.com etc
This goes right through to send, but then get a 404 status as the url is not found. I am obviously not using google in my request, but the error is the same. With "http://" it errors, but without, it doesn't error but cannot find the url.
Any thoughts appreciated.
I have found one thing, but unsure if it is related. According to W3C html 5 documentation, InvalidStateError is thown on open() if document is not fully active (when it is the active document of its browsing context). And if this is the cause of the error; how can the document not be the active document and how to I define the base url of an app that does not reside on a url (document suggests setting base to the document base url of document (or setting source origin/referrer source))?
Have gotten one step closer. After lots of fiddling about, I eventually found that for some reason on WP8 is needs the xhr to be opened before anything else is applied. So moving xhr.timeout below xhr.open sort of works.
this raises another problem in my particular case.. but that is probably another topic.

Solution for this was to move the timout to below the open.. so:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function (){
if(xhr.readyState == 4){
if(xhr.status==200){
alert(xhr.responseText);
}else{
console.log("Error: "+xhr.responseText);
}
}
}
xhr.open("POST","http://google.com",true);
xhr.timeout = 30000;
xhr.setRequestHeader("Content-Type",contentType+"; boundary=" + boundary);
//other headers / auth etc
xhr.send(bodyBuf);

Related

Subresource Integrity: How to show only warning but not block resource?

I would like to make a soft integration for Subresource Integrity attributes, so be sure that I did not break the application, but only to show a warning that I need to fix some places.
Is there an option to do so?
Secure approach
If you need some kind of flexibility, then you should use a fallback mechanism - loading required resource from another URL. Probability that two different URL's will be hacked at the same time is a lot smaller compared to hacking just one resource. Fallback doesn't violate site security, because you must trust your known-good sources which you use in your code. If your resource is a Javascript - you can use a noncanonical-src attribute for a fallback too.
Insecure approach
Now, if you really, really want a user to break server and/or client security by forcing compromised resource load - at least ask a user if he/she takes responsibility by doing so. Of course this will still be a stupid thing, it's like asking "Would you like to run a virus in your computer ?". I bet nobody would like to say YES. Anyway, here is the code, which does asking these type of questions:
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"></script>
<script>
function loadResource(path) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var cs = CryptoJS.SHA256(this.responseText);
if (btoa(cs) == 'NjBiMTllNWRhNmE5MjM0ZmY5MjIwNjY4YTVlYzExMjVjMTU3YTI2ODUxMzI1NjE4OGVlODBmMmQyYzhkOGQzNg==' ||
confirm('Bootstrap is NOT the latest version 4.3.1, load anyway ?')
) {
var link = document.createElement('link');
link.rel = "stylesheet";
link.href = path;
document.head.appendChild(link);
}
else {
var err = document.getElementById('error');
err.title = "Component version error !";
err.innerHTML = ' ⚠️';
}
}
};
xhttp.open("GET", path, true);
xhttp.send();
}
loadResource(
//'https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css' // newest boostrap
'https://stackpath.bootstrapcdn.com/twitter-bootstrap/2.0.4/css/bootstrap-combined.min.css' // old legacy
);
</script>
DEMO
I do not recommend only displaying warnings when the SRI-Hashes don't match. When see the warning as a User, it's already too late and potentially malicious scripts were executed on your machine.
However, you can implement your desired behaviour using the ServiceWorker-API and something like <script data-integrity="xxxxxxxx">. For that, you'd want to:
Register a new ServiceWorker
Listen to the fetch event
[Client.postMessage] the targetURL to your Parent
Get script integrity hash by targetURL $('script[src=event.data.targetURL]').attr('data-integrity')
and push it into the client using Worker.postMessage
hash the response using e.G. cryptojs.sha256
match the hashes inside the worker
If the hashes match, return the response. If they don't match, return the response and use Client.postMessage again to trigger a warning.

navigator.clipboard is undefined

Why is navigator.clipboard always undefined in the following snippet?
var clipboard = navigator.clipboard;
if (clipboard == undefined) {
console.log('clipboard is undefined');
} else {
clipboard.writeText('stuff to write').then(function() {
console.log('Copied to clipboard successfully!');
}, function() {
console.error('Unable to write to clipboard. :-(');
});
}
More on the clipboard API can be found here.
Chrome Version: 68.0.3440.106.
I'm sure this was working at some point, but no longer is. It's confusing because this table suggests that the Clipboard API is implemented in Chrome (has been for some time), but this table of specific API methods suggests that none of the methods of the API is supported??
This requires a secure origin — either HTTPS or localhost (or disabled by running Chrome with a flag). Just like for ServiceWorker, this state is indicated by the presence or absence of the property on the navigator object.
https://developers.google.com/web/updates/2018/03/clipboardapi
This is noted in the spec with [SecureContext] on the interface: https://w3c.github.io/clipboard-apis/#dom-navigator-clipboard
You can check the state of window.isSecureContext to learn if that's the reason a feature is unavailable. Secure contexts | MDN
And yes, you should set up HSTS to make sure HTTP redirects to HTTPS.
you can write an all-in-one wrapper function.
if in secure context (https) : use navigator clipboard api
if not : use the 'out of viewport hidden text area' trick
// return a promise
function copyToClipboard(textToCopy) {
// navigator clipboard api needs a secure context (https)
if (navigator.clipboard && window.isSecureContext) {
// navigator clipboard api method'
return navigator.clipboard.writeText(textToCopy);
} else {
// text area method
let textArea = document.createElement("textarea");
textArea.value = textToCopy;
// make the textarea out of viewport
textArea.style.position = "fixed";
textArea.style.left = "-999999px";
textArea.style.top = "-999999px";
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
return new Promise((res, rej) => {
// here the magic happens
document.execCommand('copy') ? res() : rej();
textArea.remove();
});
}
}
use :
copyToClipboard("I'm going to the clipboard !")
.then(() => console.log('text copied !'))
.catch(() => console.log('error'));
ps : do not try it in a repl like jsfiddle/copeden/...
Try this:
if (typeof (navigator.clipboard) == 'undefined') {
console.log('navigator.clipboard');
var textArea = document.createElement("textarea");
textArea.value = linkToGo;
textArea.style.position = "fixed"; //avoid scrolling to bottom
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
toastr.info(msg);
} catch (err) {
toastr.warning('Was not possible to copy te text: ', err);
}
document.body.removeChild(textArea)
return;
}
navigator.clipboard.writeText(linkToGo).then(function () {
toastr.info(`successful!`);
}, function (err) {
toastr.warning('unsuccessful!', err);
});
In localhost, the clipboard is blocked by the chrome browser. You check this by going to the following path
Chrome > settings > privacy and Security > site settings > View permissions and data stored across sites then click on your localhost URL which will mentation on the page and check the permission of the clipboard
A minimal solution for copying tooltips when HTTPS is not yet available and the solution with document.execCommand('copy') does not work.
But it requires that the user selects and copies by hand what is displayed in the alert.
function copyToClipboard(text) {
if(navigator.clipboard) {
navigator.clipboard.writeText(text);
}
else{
alert(text);
}
}
This solutions works at the moment (it includes cross browser support, error handling + clean up).
https://stackoverflow.com/a/33928558/318380
you can use :
change the :
navigator.clipboard.writeText("Content")
to :
navigator['clipboard'].writeText("Content") instead.

GoogleSpreadsheets UrlFetchApp.fetch having problems getting data

I'm trying to get stock data from yahoo using the method found here http://www.gummy-stuff.org/Yahoo-data.htm and when using UrlFetchApp.fetch on any stock URLs, it fails most of the time. Note that the same url works perfectly if I navigate to it through my browser.
Code,
var resp = UrlFetchApp.fetch("http://finance.yahoo.com/d/quotes.csv?s=" + securityName + "&f=sl1d1t1c1ohgv&e=.csv");
Where securityName is a stock symbol like AAPL or MSFT. Usually the error is address unavailable. It always works when I navigate to it through my browser.
The error is associated with yahoo site.
I made the test through javascript and had the same problem.
If you want to test access download.finance.yahoo.com and them open chrome console via F12 and put the code bellow:
function test() {
for(var x = 0; x < 100; x++) {
var req = new XMLHttpRequest();
req.open("GET", "http://download.finance.yahoo.com/d/quotes.csv?s=AAPL&f=sl1d1t1c1ohgv&e=.csv", false);
req.send();
if(req.status != 200) {
console.log("ERROR"); return;
}else {
console.log("OK");
}
}
}
test();
Check in my example that it worked 8 times (8 OK's) but in the 9th try it failed.
I am using the same script for months and the error has started appearing only recently, seems like Yahoo! screwed something up.

How to pass data back to webpage?

I am working on a WP8 application, containing the WebBrowser control in which I open a html page, containing javascript. The javascript contains the following function:
function send(data) {
windows.external.notify(data);
var xhr = new XMLHttpRequest();
xhr.open('GET', 'getresponse', false);
xhr.send(null);
var result = xhr.responseText;
if (result) {
return JSON.parse(result);
}
}
Basically this function calls the native C# side of the app, where I run some functions and I need to be able to return some data from the native side to the send function. I wanted to use an XMLHttpRequest for this, where my idea was to "intercept" the request url (in this case 'getresponse') and return the data I want by including it in the response.
Is this please possible on Windows Phone 8 using the WebBrowser control?
Once again, all I need to do is this:
Have a javascript function (in this case called "send") which connects to the native app (using windows.external.notify) and pass data back to this "send" function so that it can return it (and so that other JS function can use it).
Is this please possible? If not using the XMLHttpRequest, maybe using another technique?
Thank you all for your help!
You are looking for InvokeScript.
If you have full control over the page that is displayed inside the WebBrowser (e.g. the server is your's), you can define the JS-function to be called:
webBrowser.InvokeScript("yourJSFunction", "param1", "param2");
If you display a website from a foreign webserver you can inject JS like this (this uses jQuery):
webBrowser.InvokeScript("eval", "window.youInjectedFunction = function() {" +
"window.external.notify('and_notify_back');" +
"}; " +
"window.readyStateCheckInterval = setInterval(function() {" +
"window.external.notify('timer');" +
"if (document.readyState === 'complete') {" +
"clearInterval(window.readyStateCheckInterval);window.yourInjectedFuntion();" +
"}}, 100);" +
"");
I used the timer, as you can not be certain if the InvokeScript is called after the page is completely loaded.
If you can control the source, you should definitely go for option 1.

Chrome addon with my server interaction

its many days reading hundreds of ways to help me make what I really need. No success at all.
What I need is this:
1) Having a button which only works when the tab has a certain url.
2) After clicking it, must read page's source and then get some pieces of it to send them to my server page in order to check my database for recordcounts (I assume with AJAX & javascript). Then this page should send back to the extension its responses and populate the popup html.
Looks easy I know, but please I need the workflow if not the required codes for the extension.
Thank you so much!
ok so you can chceck selected tab and it's url with:
chrome.tabs.getSelected(null,function(tab) {
workWithUrl(tab.url);
});
...
function workWithUrl(url){
if (url == ...
...
}
To be able to chceck this you need to add permission for "tabs"
To process page source code, send it to web service and change popup.html:
var xhr = new XMLHttpRequest();
xhr.open("POST", "__server adress___", true);
//headers
xhr.setRequestHeader("Content-Type", "application/json");
//response
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
//response from service to popup.html
document.body.innerHTML = xhr.responseText;
}
}
//process page here
xhr.send(pageText);
You have to add permission for server adress to manifest as well and everything should be executed from popup.js (or html).