I am using the excellent file-collection package,
https://atmospherejs.com/vsivsi/file-collection
to store images in my Mongo database. Running the app on Android doesn't show the images (they appear as broken images). In the browser it is perfect.
I don't think the problem is unique to this package, as it is using Mongo's gridfs to store the images, and provides URL's to access them.
Here is a note from Vaughn in the documentation:
Cordova Android Bug with Meteor 1.2+
Due to a bug in the Cordova Android version that is used with Meteor
1.2, you will need to add the following to your mobile-config.js or you will have problems with this package on Android devices:
App.accessRule("blob:*");
Which I have done, but without success.
I also see the documentation references setting headers to deal with CORS issues, like this:
myFiles = new FileCollection('myFiles',
{ resumable: true, // Enable built-in resumable.js chunked upload support
http: [ // Define HTTP route
{ method: 'get', // Enable a GET endpoint
path: '/:md5', // this will be at route "/gridfs/myFiles/:md5"
lookup: function (params, query) { // uses express style url params
return { md5: params.md5 }; // a query mapping url to myFiles
},
handler: function (req, res, next) {
if (req.headers && req.headers.origin) {
res.setHeader('Access-Control-Allow-Origin', 'http://meteor.local'); // For Cordova
res.setHeader('Access-Control-Allow-Credentials', true);
}
next();
}
},
But again without success.
Looking at the network tab on the inspector, I can't even see requests for the images from the server, which suggests that it is being denied by something in the Cordova code, and it's not even trying to go out and get the images.
I have reproduced the problem using Vaughn's demo app, which I have forked and added the android platform, so it's ready to go if you care to try and help.
https://github.com/mikkelking/meteor-file-sample-app
If you do a meteor run android-device it should run on the Android. You will need to register and then upload an image to see the problem. From a browser it works fine.
Any help would be appreciated, this is a show stopper for my project. One option I have considered is to move the images to an S3 bucket, which I think should work, but I'd like to keep the images in the db if I can.
I had a similar issue once with gridfs. I believe that the issue comes because the image source is a relative source. So your image sources are coming from localhost. It works on the web version because the browser is on the same machine as your server, so a localhost source works fine. But on the android device it won't work because the images are not served on that device.
When I had this problem I just deployed to production and it worked on mobile devices because the image source pointed to a url that was on the internet and not relative to the device. This works for production but not for dev testing.
When I saw this question I cloned your code and got it working on an android device for local dev.
The first step I did is to set the ROOT_URL env variable and mobile server to point to the your local server. When you run meteor locally you can run a command like this to set these variables, using your computer's local ip address
export ROOT_URL=http://192.168.1.255:3000 && meteor run android-device --mobile-server=http://192.168.1.255:3000
Next, in your sample.coffee Template.collTest.helpers link function, you need to use the absolute url instead of a relative one (so that on your mobile device it will look to your local server instead of localhost). To dynamically get this so that it works on different servers, you can use something like this
Meteor.absoluteUrl(myData.baseURL + "/md5/" + this.md5)
Then I had to add the computer's ip address http://192.168.1.255:3000 to the content security policies in the sample.jade file.
I almost forgot, at this point I was getting a 403 forbidden error. I changed the myData.allow read function in sample.coffee and just returned true and the 403 was gone, something was happening with the permissions there
After that the image showed up on my android device.
Related
I'm trying protractor to write a few tests in a non angular application. I have to login in a page trough basic authentication in google chrome, but i have no idea how.
I already tried baseUrl: 'https://username:password#url' and capabilities: {
'browserName': 'chrome',
'chromeOptions' : {
args: ['--login-user=foo', '--login-password=bar']
}
}
But none if these worked for me. Anyone knows how to do it? I'm having some hard time on it.
You can set the URL as http://username:password#yourdomain.example. Chrome will handle it!
The short answer is there is no easy way of doing it on chrome because they do not support modifying request headers -- see https://code.google.com/p/selenium/issues/detail?id=141 (title says response headers, but if you read it, it's for all headers).
That being said, there are ways to do it, albeit difficult.
1) Find a chrome extension/plugin that allows you to modify header. A simple search bring up many of them: https://chrome.google.com/webstore/search/modify%20header. You'll need to add the plugin to webdriver: see Is it possible to add a plugin to chromedriver under a protractor test?.
2) You can use browsermob-proxy (https://github.com/lightbody/browsermob-proxy); this way you route your traffic through the proxy, which would add the headers for you.
From the docs:
POST /proxy/[port]/auth/basic/[domain] - Sets automatic basic authentication for the specified domain
Payload data should be json encoded username and password name/value pairs (ex: {"username": "myUsername", "password": "myPassword"}
There's a node project that may help you, https://github.com/zzo/browsermob-node, but you would still need to set up your proxy server yourself.
Both ways for chrome are complex, but would get you what you want. (or you can stick with firefox and follow Robert's answer)
As of version 59 Chrome no longer supports URLs with embedded credentials.
To work around this I wrote the authenticator-browser-extension Node module, which might be useful if you're using Protractor, WebDriver.io or similar test runners.
To use the module install it from npm:
npm install --save-dev authenticator-browser-extension
And import in the protractor.conf.js:
const { Authenticator } = require('authenticator-browser-extension');
exports.config = {
capabilities: {
browserName: 'chrome',
chromeOptions: {
extensions: [
Authenticator.for('username', 'password').asBase64()
]
}
},
}
Pro tip: remember not to commit your credentials with your code, consider using env variables instead.
Hope this helps!
Jan
It's because Firefox doesn't trust any site by default with sending the Windows auth info over. Even if you change it in the configurations manually, it won't affect protractor because it opens Firefox with an isolated configuration each time you run your end to end tests.
You'll need to programatically set up a Firefox profile and set its preferences such that it would trust localhost (or some other website, depending where the pages are loaded from)
First, check out this example. It shows how you can set up the profile and how you can set preferences.
https://github.com/juliemr/protractor-demo/tree/master/howtos/setFirefoxProfile
What it does is that it modifies the homepage for each new tab. In the same manner (with the firefoxProfile.setPreference method) you can change the preferences responsible for trusting websites. They're called "network.automatic-ntlm-auth.trusted-uris" and "network.negotiate-auth.delegation-uris". You'll need to set them both to "localhost". (Again, if they're at some other place, it's obviously that URL)
hankduan's browsermob-proxy solution worked for me on Chrome - but the latest revisions of browsermob are using a thing called littleproxy which does not support auth headers. Thusly I had to do browsermob-proxy -port 9090 --use-littleproxy false, which got things working.
You may use Windows Credentials Manager to avoid this pop-up being constantly shown on every attempt to log in.
Add your credentials to the 'Generic' category there, restart browser (including background apps running).
Some explanation I currently have: this pop-up is not 'browser' specific, it is 'in the middle', between browser and domain credentials verification. Thus browser features (save password, autofill) do not work completely. By the same reason Protractor / Selenium etc. do not have complete control over that pop-up - it is by design of the domain authentication.
As not completely sure if it is the only reason there are some other hints:
- you may also need to add your site to the IE (IE, not Chrome) list of trusted sites (Chrome grabs information from there);
- check "Automatic logon with current user name and password" in IE (not Chrome) - may not work if credentials you are using for the site are different from those you use to login to the machine.
If you're reading this in 2019, with Angular 7/8, consider this:
https://www.npmjs.com/package/authenticator-browser-extension
I find it much easier than the solutions suggested above.
I'm building a website using WordPress as a backend, and AngularJS as the frontend. I'm using the WordPress JSON API to get my data to the front-end.
https://wordpress.org/plugins/json-api/
The problem
I'm using AngularJS to get my data from the WordPress JSON API. I have created the following service:
this.getPage = function ( slug ) {
return $http.get('wordpress/api/get_page/?slug=' + slug)
}
I use this service in my controller to get the current page like this:
HTTPService.getPage('home')
.success(function ( data ) {
$scope.page = data.page;
console.log(arguments);
})
.error( function () {
console.log(arguments);
})
This is working fine in all browsers, except for Safari on iOS. On Safari on iOS I get the following response when I log the error arguments:
This is the safari debugger which showed when I connected my iPhone to my Mac. The error response which I get is error code 0..
What I have tried so far
I have set Access-Control-Allow-Origin "*" in the .htaccess file, but this doesn't seem to work. The request is done on the same domain with a relative URL, so I don't think that this is the problem.
So, does anyone know why this is not working on Safari (iOS)?
EDIT
Some extra information as requested:
I'm pretty sure that this is due to the fact that Safari is the only browser that has the policy of blocking "3rd party cookies and other website data" by default. Actually, this issue shouldn't be exclusive of Safari iOS, it should also happen with Safari on your OSX. I'm pretty sure that if it's not happening in your MacBook is because one day you changed the default settings of the "Privacy".
You can try this, open Safari, go to "preferences" and under the tab "Pricacy" check if you have the option: "Block cookies and other website data" set to "From third parties and advertisers". This is the first, and the default option in the modern versions of Safari.
In your MacBook it will look like this:
And in iOS it will look like this:
Just to confirm that this is in fact what's causing your issue: change this setting to "Never", clear the cache and try to reproduce that problem again. I'm quite confident that you won't be able to reproduce it.
Now, if you set it back to "Block cookies and other website data: From third parties and advertisers" and you first clear the cache, you will have that problem again (with either iOS or OSX). After you've confirmed that this is the cause of your problem, set this setting back to "From third parties and advertisers", so that you can reproduce and address the problem with the default settings.
Bare in mind that every time that you want to re-test this issue you will be better off clearing the cache of Safary. Otherwise it could happen that Safari decides that the site serving the API can be trusted and you won't be able to reproduce the issue. So, just to be sure, clear the cache every time that you test this.
I believe that the root of this problem is that Safari wants to make sure that the user has had a direct interaction with the page that it's serving the "3rd party content" before the main page loads that content.
I would need to know more about your project in order to suggest an "optimal" solution. For instance: will the final app be integrated under the same domain as the API? Because if that's the case, you shouldn't have that issue when you go to production. I mean, if the app that you are developing will be hosted under: http://whatever.yourDomain.org and the API is going to be part of that same domain (yourDomain.org), then you shouldn't have that issue at all in production.
On the other hand, if you need to have have the API hosted under a different domain, then you will have to find a way to "trick" Safari. Have a look at this:
Safari 3rd party cookie iframe trick no longer working?
And this:
http://www.allannienhuis.com/archives/2013/11/03/blocked-3rd-party-session-cookies-in-iframes/
I hope that this helps.
I made an application using apache cordova. my server is written in node.js running locally and port 3005. So I want to make API call from cordova I am using backbone in client side.
I written the following code to make API call
makingAPICallForStatus:function(){
var userSessionModel = Backbone.Model.extend({ //Creaating a model for checking user session status
url:"http://localhost:3005/api/user/status/",
});
var userSessionModelObj=new userSessionModel();
this.makeApiCall(userSessionModelObj,"",'GET',function(model,response,options){console.log(response);});
},
makeApiCall:function(modelObj,dataObject,requestType,successCallback){
modelObj.fetch({data:dataObject,
type:requestType,
success:successCallback,
error:function(){console.log("error")}
});
}
If you observe, I mention URL path is :"http://localhost:3005/api/user/status/". This way it's not working. it's showing This request has no response data available
Now I tried with production domain like
URL path is :"http://xxx.xxxx.com/api/user/status/"
This way it's working fine.
Why localhost was not working, I invoke same url directly in my browser working fine. but it's not working in cordova.
Note : I didn't modify anything in www/config.xml file.
What's the problem how can I fix this.
Thanks.
localhost is an alias of 127.0.0.1 even if you are running on an emulator on the same machine, local host is not real. You have to always make calls to an ipaddress or domain name from a device (even virtual devices). This is because on the device localhost is referring to the device not the machine that it may be running from.
I'm porting an ajaxed, mobile-optimized website to PhoneGap, but have been unsuccessful in getting any POST to the server. From what I've read, xhreq POSTS are supposed to be possible in PhoneGap.
The specifics: I'm targeting the Android platform using the latest Cordova 3.3.1-0.1.2, the latest Android SDK, and a Galaxy S3 updated by Verizon to Android 4.3. Connectivity is over wifi to my local server. In every attempt, the POST arrives at the server as a GET, with no post data (verified using tcpdump to inspect packets). The mobile-optimized web site works fine in the browser on the same phone, also over wifi.
I've isolated the fail case by creating a brand new Phonegap project, nothing more than:
$ cordova create Hello
$ cd Hello
$ cordova platform add android
Then in index.js, at the end of the onDeviceReady handler, adding a snippet I first tested in a simple browser page (domain substituted here):
// TEST POST CAPABILITY
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState==4 && (req.status==200 || req.status==0)) {
console.log("POST Response: " + req.responseText);
}
};
var t = new Date().getTime(); // Just to foil any caching
req.open("POST", "http://mydomain.com/services/rpc?t=" + t, true); // async
req.setRequestHeader('Content-type','application/text; charset=utf-8');
var postContent = JSON.stringify({id:t, method:"misc.log", params:[{log:"POST Test"}]});
req.send(postContent);
And then run on the phone with:
$ cordova run android
It fails like the fuller app, arriving at the server as a GET with no post data. I verified a couple of configuration item defaults to make sure they were as required:
In config.xml:
<access origin="*" />
In AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
Any ideas as to what might be going wrong, or other things to look in to?
Thanks.
Your content type should be set to
"application/json".
JSON.stringify() creates JSON content.
Next, can you tell us how your server process is determining the request type. Can you post the relevant code?
I would start by adjusting the content type value. See if that makes a difference.
Hope that helps.
The problem was an ip forwarding one, just not the one I'd originally suspected (forwarding to & from port 80 to my local server on port 8080, which I've used for years as a convenience to allow not having to add :8080 into the browser url all the time).
It was this:
In the MX records for "mydomain.com", I had www.mydomain.com pointing to my server's IP address, but the root mydomain.com (the host address I was using in the url to XMLHttpRequest), redirecting to www.mydomain.com.
This worked in a normal browser session, as if you type in mydomain.com, it just goes to www.mydomain.com, then runs from there - and it would use all relative paths in the xhreq's.
In PhoneGap, however, which requires the full path be specified, the POSTs were not making it through the redirect. It was also causing sluggish image loading behavior and some bizarre communication hangups after many loads - I just hadn't realized the problem had the same root cause (rather I was getting worried about WebView performance).
The great news is that POST is working fine now, and the WebView appears to be plenty speedy for my needs.
To summarize the solution: make sure that the subdomain (or lack thereof) in fully qualified urls passed to XMLHttpRequest (as required in PhoneGap) are mapped to an ip address (A record), and not redirected, in the MX records for your domain.
I'm writing an app in Cordova/PhoneGap which tries to fetch a file from Dropbox using Dropbox.js. Cordova version is 3.0.1 and Dropbox.js version is 0.10.0. My Javascript works just fine on a desktop browser with this:
var client = new Dropbox.Client({ key: "<my key>", secret: "<my secret>"} );
client.authenticate(function(error, client) {
...
But in the Cordova-packaged app I get an error: "It seems the app you were using submitted a bad request".
I suspect the problem has to do with the redirect-url which resolves to this in the Cordova app:
Dropbox.AuthDriver.BrowserBase.currentLocation()
-> file:///android_asset/www/index.html
Urls starting with file:/// will not work properly with Dropbox API even if I add them to OAuth redirect URIs in Dropbox API console.
The Cordova app does work fine if I know the uid and token before:
var client = new Dropbox.Client({
key: "<my key",
secret: "<my secret>",
token: "<token>",
uid: "<uid>"
});
client.authenticate(function(error, client) {
...
This way I can read my dropbox files just fine. Problem is that the token doesn't last forever and I 'd like to get a new one from my app itself.
According to this discussion, this issue should already have been resolved in an earlier version of dropbox.js (0.9.2). But I still run into it. I wonder if I should use the API a bit differently, but I don't know how.
Dropbox.js has added a redirectUrl option in this commit I just don't know exactly what should I put there in my Cordova app. The file:///android_asset/www/index.html will not work because Dropbox API does not allow file urls.
Simon McDonald's answer to this question might help. But that means I have to have an external server-hosted page with the dropbox.js login functionality. Or could I use the main dropbox web login page instead?
dropbox.js 0.10.1 has some fixes for Cordova.
We have just set up a page that you can use as the OAuth 2 redirect URL in embedded WebViews, when file:// doesn't work.
https://www.dropbox.com/1/oauth2/redirect_receiver