Does PhantomJS support cookies? If yes, where can I find the API details?
I am not able to figure it out after searching for a while now.
Yes, as of 1.7 Phantom has complete cookie handling, enabled by default. Cookies are retained for the duration of the process's life.
If you'd like to retain cookies across runs of Phantom, there's a command-line option cookies-file where you can specify where to store persistent cookies.
--cookies-file=/path/to/cookies.txt specifies the file name to store the persistent cookies.
In page script, you can use the regular document.cookie property. Like in browsers, this property returns a string similar to that which would be sent in the Cookie: HTTP header.
In Phantom script, you can access cookies for a page (subject to the usual origin restrictions) via page.cookies, which returns objects.
You can also access all cookies (from all domains) using phantom.cookies.
var page = require('webpage').create();
page.open('http://example.com', function (status) {
page.evaluate(function() {
document.cookie; // => "test=test-value;"
});
page.cookies; // => [{
// domain: "example.com",
// expires: "Wed, 08 Jan 2014 00:00:00 GMT"
// httponly: false,
// name: "test",
// path: "/",
// secure: false,
// value: "test-value"
// }]
phantom.cookies; // contains ALL cookies in Phantom's jar
});
To add/edit/delete cookies, use the addCookie, deleteCookie, and clearCookies methods of either a WebPage object or the phantom object.
When you use the methods of a WebPage object, you only modify the cookies that are visible to the page. Access to other domains is blocked.
However, using phantom's cookie methods allow access to all cookies. phantom.addCookie requires a domain (WebPage.addCookie assumes the current domain if you don't specify one), and phantom.deleteCookie deletes any cookie matching the specified name.
It does, through WebPage.addCookie() - which incidentally doesn't work neither for me nor someone else.
You can use this instead:
phantom.addCookie({
'name': 'mycookie',
'value': 'something really important',
'domain': 'example.com'
})
page.open('http://example.com/url/path/', function() {
console.log(page.cookies);
})
The work around I had to do was to execute javascript directly. I am using Geb and did the following:
js.exec("document.cookie='PHPSESSID=${cookie}';")
When selenium fails I always fall back to javascript for functionality.
I haven't tried it yet, but doesn't --cookies-file=/path/to/cookies.txt work?
It's the first item in API reference...
I had graded information within session recently. You should set cookie in page object, like below (coffeescript):
#page.clearCookies()
#page.addCookie
'name' : "JSESSIONID"
'value' : "0000rN3YAlVAU0xdHkKc6BEzWj9:-1"
'domain' : 'some.domain.com'
'path' : '/'
Related
I am developing a firefox addon. i use localStorage to save some data and retrieve.
function to check if it is available or not
if(!localStorage.getItem('font')) {
populateStorage();
}else{
var aValue = localStorage.getItem('font');
alert(aValue);
if not then create
function populateStorage(){
localStorage.setItem('cname', name);
localStorage.setItem('font', 'Helvetica');
localStorage.setItem('image', 'myCat.png');
}
This is perfectly working localhost but if i visit other host like google.com and try to get i am getting error not found
if(!localStorage.getItem('font')) {
alert('Not found !!!!');
}else{
var aValue = localStorage.getItem('font');
alert(aValue);
}
is there any way to fix this issue ? or am i doing it in wrong way ?
LocalStorage is intended to be accessible only from the same host. This allows different websites to have a different scope for their data, and also ensures that one website cannot access data from another website.
From MDN,
The read-only localStorage property allows you to access a Storage object for the Document's origin; the stored data is saved across browser sessions.
From: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
If you need to share data across different domains, you should use server-side persistence.
From what I've undestood local storage is not cross domain solution, so this behavior is correct.
What you need to do is fallow MDN solution. I've found something like this:
// define 2 objects
var monster = {
name: "Kraken",
tentacles: true,
eyeCount: 10
}
var kitten = {
name: "Moggy",
tentacles: false,
eyeCount: 2
}
// store the objects
browser.storage.local.set({kitten, monster})
.then(setItem, onError);
(code copied from MDN > JavaScript APIs > storage )
In this solution data will be pinned to browser/extension, not to domain. But be aware, that data still will be destroyed when user clear browser cache or something like that.
We have a javascript api.js which is hosted on domain api.abc.com. It manages the local storage.
We included this javascript in our websites at abc.com and login.abc.com as a cross domain js like
<script src="http://api.abc.com/api.js">
I understand that localstoarge is per domain basis. However since api.js is loaded from api.abc.com, I expected that it will have access to local storage of api.abc.com from both the domains. Unfortunately, it doesn't seem to be the case. When api.js stores a value in localstoarge from one domain, it's not accessible to it when loaded from other domain.
Any idea?
How about using cross domain postmessage and iframes?
So on your wrong-domain-page you include an iframe that posts messages with the cookie data back.
Here is a solid example of cross domain postmessages:
http://blog.teamtreehouse.com/cross-domain-messaging-with-postmessage
live example:
http://codepen.io/anon/pen/EVBGyz //forked sender code with a tiiiiiny change :) :
window.onload = function() {
// Get the window displayed in the iframe.
var receiver = document.getElementById('receiver').contentWindow;
// Get a reference to the 'Send Message' button.
var btn = document.getElementById('send');
// A function to handle sending messages.
function sendMessage(e) {
// Prevent any default browser behaviour.
e.preventDefault();
// Send a message with the text 'Hello Treehouse!' to the new window.
receiver.postMessage('cookie data!', 'http://wrong-domain.com');
}
// Add an event listener that will execute the sendMessage() function
// when the send button is clicked.
btn.addEventListener('click', sendMessage);
}
Receiver code:
window.onload=function(){
var messageEle=document.getElementById('message');
function receiveMessage(e){
if(e.origin!=="http://correct-domain.com")
return;
messageEle.innerHTML="Message Received: "+e.data;
}
window.addEventListener('message',receiveMessage);
}
As noticed in your post the localStorage (sessionStorage too) won't be stored on the storage related to the domain api.abc.com. If this was the case, by using CDN version of a library using localStorage you would have to share storage with all the other websites using this library.
One good solution could be to use an iframe with postMessage as explained in the following stack overflow:
use localStorage across subdomains
You might try this cross-storage from Zendesk. Basically,
There are hubs and clients:
hubs: reside on any server, interact directly with LocalStorage API
clients: load the hub using an embedded iframe, and post messages, interact with data
Key things is you can configure the permission (get, set, delete) that each host or domain client could have.
The library is divided into two types of components: hubs and clients.
Care should be made to limit the origins of the bidirectional
communication. As such, when initializing the hub, an array of
permissions objects is passed. Any messages from clients whose origin
does not match the pattern are ignored, as well as those not within
the allowed set of methods. The set of permissions are enforced thanks
to the same-origin policy. However, keep in mind that any user has
full control of their local storage data - it's still client data.
This only restricts access on a per-domain or web app level.
The other answers all ignore the fact that you're not really operating cross-domain, just between subdomains.
You still need a hidden iframe to encapsulate the origin of the localStorage store you want to access (api.abc.com), but by setting document.domain = "abc.com" on both main window and hidden iframe, they can interact directly. (Though note that this is deprecated, may have security implications, and in Chrome at least requires also sending a Origin-Agent-Cluster: ?0 header).
Then you can literally just use hiddenIFrame.contentWindow.localStorage instead of window.localStorage, and forget about the headache of doing anything via postMessage().
I posted a more detailed version of this answer here: https://stackoverflow.com/a/63602446/999120
Use iframe to store data in local storage & postMessage API to communicate between parent domain & iframe
Create Iframe with message event listener to store data in local storage of iframe domain
window.addEventListener("message", handleMessage, false);
function handleMessage(e) {
let {key, value, method} = e.data;
if (method == 'store') {
window.localStorage.setItem(key, value); // Store data in iframe domain local storage
} else if (method == 'retrieve') {
let response = window.localStorage.getItem(key);
e.source.postMessage({
key,
response,
method: 'response'
}, '*'); // Retrieve local storage data
}
}
Pass Message from parent domain to iframe to store data
document.getElementById('myFrameId').contentWindow.postMessage({
key: 'key',
value: data,
method: 'store'
});
Retrieve data from Iframe
document.getElementById('myFrameId').contentWindow.postMessage({
method: 'response',
key: 'key'
});
window.addEventListener("message", handleResponse, false);
function handleResponse(e) {
let {key,value,method} = e.data
if (method == 'response') {
console.log('Response Key', key);
console.log('Response value', value)
}
}
I'm using cookies that should be deleted after user closes the page, but they're not. This is how I set cookies with JS
document.cookie="status=false";
I can see the cookie in console and after I close browser and open it again and go to my webpage there's still cookie status=false any idea why?
I solved it with this "trick", I don't know why I can't get cookies to work
window.onbeforeunload = function() {
document.cookie="status=false";
};
document.cookie = ... sets individual cookie values, it does not set "the entire cookie" to the string you passed, so setting "status=false" simply binds or updates the "status" value, irrespective of whatever else is in the cookie:
document.cookie = "cow=bell";
document.cookie = "cat=lol";
// cookie is now "cow=bell&cat=lol", not just "cat=lol"
If you want to delete the entire cookie, set its expiration time to "in the past" and the browser will do the cleanup for you.
(As pointed out in a comment, if you never set an expiration timestamp for your cookie, it'l expire when the page session ends, e.g. you close the tab/browser)
I was actually doing this today. A great reference is the Mozilla cookie documents if you create a js with their var docCookies code then using the functions provided like docCookies.setItem() docCookies.setItem() docCookies.getItem() or docCookies.removeItem() work incredible well.
I am trying to login to a website with phantomJS by session AUTH cookie, I finished the code for it and everything is working perfect, the problem is the website have like another login system inside with the same cookie, once accessed the other page cookie will update the security auth token, so when I add the First cookie to phantom I see that it is set to read Only because i cant access what is inside the second login system as Website is trying to update the Cookie that I manually added but unfortunately it fails because the cookie is Set to read Only.
code I am using :
phantom.addCookie({
'name': 'some name here', /* required property */
'value': 'some hash here',
'domain': 'ea.some domain here.com', /* required property */
'path': '/',
'httponly': false,
'secure': false,
'expires': (new Date()).getTime() + (10000 * 60 * 60) /* <-- expires in 10 hour */
});
I tried to delete the session cookie before my script auto access the page that needs second Auth but it just log me out because i need to have my old Session auth so it can be updated with the new session authhash.
any ideas how to make manually added cookies to be updated once requested from server side ?
I found the solution,
It appears that server actually created a new cookie with the same name and new value. not by replacing it with the new value. I searched the web for any help regarding this matter but I failed, I fixed this problem by taking the value of the new cookie and saving it to a variable, then executing phantom.clearcookies() to remove all the cookie and adding the new cookie again with the new value that I stores, It was not clean but it did the trick.
I am using jQuery to access/set the cookies. I have planted a cookie named CookieNo1 at path /.
I planted this using the url localhost:8080/audi.
The cookie value is stored, which I checked manually on the firefox cookies. Now when I try to access the same cookie, using the url localhost:8080/audi/products using $.cookie('CookieNo1');
This doesn't seem to retrieve the value of the cookie. It returns a null value. However when I try to write the cookie using the same localhost:8080/audi/products url, it overwrites the previous cookie value. Please help me with this issue.
All I need is $.cookie('CookieNo1') to return the previous cookie value instead of null.
Thanks in advance
You have to set the expiry date. Otherwise, the cookie is removed at the end of the session. In JQuery: $("CookieNo1", "value", {expires: 7}) (this cookie stays for 7 days).
In JavaScript:
document.cookie = "CookieNo1=value; max-age=604800";
max-age sets the maximum lifetime of a cookie, in seconds.
EDIT
Quote from comments:
#RobW I added the cookie using jquery on the page
http://localhost:8080/audi with the code $.cookie("asdftraffic",
valueToSet, { expires: 30, path: '/', secure: true }); I try to
retrieve the cookie from the url http://localhost:8080/audi/products
using '$.cookie('asdftraffic');' which returns null.
Your issue is caused by secure: true. This attribute requires the cookie to be transmitted over a secure connection (https). Remove the secure: true flag if you're not using an encrypted connection.
First you set the cookie:
var myvalue = 100, 2000, 300;
$.cookie("mycookie", myvalue);
Then you get the cookie:
var getmycookie = $.cookie("mycookie");
var myvalues = getmycookie.split(",");
var firstval = myvalues[0];
var secondval = myvalues[1];
var thirdval = myvalues[2];
Should'nt be much harder.
When not specifying an expiration, the cookie is deleted on session end i.e. when the browser is closed.
EDIT: You can also specify the path:
$.cookie("mycookie", myvalue, {
expires : 10, //expires in 10 days
path : '/products', //The value of the path attribute of the cookie
//(default: path of page that created the cookie).
domain : 'http://localhost:8080', //The value of the domain attribute of the cookie
//(default: domain of page that created the cookie).
secure : true //If set to true the secure attribute of the cookie
//will be set and the cookie transmission will
//require a secure protocol (defaults to false).
});
I would think something like this would do:
var myvalue = 100, 2000, 300;
$.cookie("mycookie", myvalue, {path : '/audi/products'});
Oh, and a session ends when the browser is closed, not when the page is unloaded, so a session cookie will do.