Firefox webextension API - Kill cookies - firefox-addon

How to kill specific cookies using the webextension API?
I can fetch the cookies using -
browser.cookies.getAll({domain: cookieDomain})
But to remove cookies, I require both the url and name,
browser.cookies.remove({name: cookie.name, url: cookie.domain})
And, domain cannot be passed to url parameter to remove.
Also, I don't get the url from the cookie object.
Then, how do you remove specific cookies?
Thanks.

You should be able to construct the url by concatenating cookie.domain and cookie.path, and you get the protocol by checking cookie.secure:
const cookieName = cookie.name;
const cookieProtocol = cookie.secure ? 'https://' : 'http://';
const cookieUrl = cookieProtocol + cookie.domain + cookie.path;
browser.cookies.remove({name: cookieName, url: cookieUrl}).then(
() => {
console.log('Removed:', cookieName, cookieUrl);
}
).catch(
(aReason) => {
console.log('Failed to remove cookie', aReason);
}
);

Related

OAuth implicit grant - Can't get the URL fragment, which contains the access token

I'm trying to implement the implicit grant OAuth flow using AWS Cognito. In particular, after having already logged in to my website, I'm trying to make a GET request to Cognito's AUTHORIZATION endpoint; the response from this request should redirect me to a URL of my choosing - let's call this the callback URL - and provide the desired access token in the fragment.
If I make this request by entering into the browser's address bar the appropriate URL for the AUTHORIZATION endpoint, everything happens as expected: The browser gets redirected to the callback URL, and the access token appears in the fragment of this URL.
However, if I make this same request asynchronously from a script in my website using XMLHttpRequest, I am unable to access the fragment returned in the callback URL (and Chrome's network tab shows that the token-containing fragment is in fact returned, just like in the address bar scenario described above). How can I access this fragment?
My code is as follows:
let xhr = new XMLHttpRequest();
let method = options.method.toUpperCase();
let extractFrom = ['url', 'code'];
xhr.open(options.method, options.url, true);
xhr.withCredentials = true;
for (const key in options.headers) {
xhr.setRequestHeader(key, options.headers[key]);
}
xhr.onreadystatechange = function () {
const status = this.status;
const respUrl = this.responseURL;
const respHeaders = this.getAllResponseHeaders();
const respBody = this.response;
if (this.readyState === XMLHttpRequest.DONE) {
if (status === 200) {
let val = extractParameter(extractFrom[0], respUrl, extractFrom[1]);
resolve(val);
} else {
console.error('Other Response Text: ' + this.statusText);
reject(this.statusText);
}
}
};
xhr.onerror = function () {
console.error('Error: ' + xhr.statusText);
reject(this.statusText);
};
xhr.send(null);
The fragment is client site stuff, only stays in browser. You will need use javascript to pull it explicitly, see https://openid.net/specs/openid-connect-core-1_0.html#FragmentNotes. You could avoid fragment by using response_mode=form_post if OpenID Connect server supports it, see https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html.

Delete all Cookies in Electron desktop app

I am using oauth (Stack Overflow) in an electron desktop app and there is a webview which loads the oauth url. I have a signout button in my app which will signout the user from Stack Overflow website and also from the app. How can I do this ?
How to remove all session cookies from the webview in electron app ?
You can remove cookies using Electron's cookies.remove() function (https://electron.atom.io/docs/api/cookies/#cookiesremoveurl-name-callback)
The trick is to convert cookie.domain into url.
import { session } from 'electron';
export default function deleteAllCookies() {
session.defaultSession.cookies.get({}, (error, cookies) => {
cookies.forEach((cookie) => {
let url = '';
// get prefix, like https://www.
url += cookie.secure ? 'https://' : 'http://';
url += cookie.domain.charAt(0) === '.' ? 'www' : '';
// append domain and path
url += cookie.domain;
url += cookie.path;
session.defaultSession.cookies.remove(url, cookie.name, (error) => {
if (error) console.log(`error removing cookie ${cookie.name}`, error);
});
});
});
}
If you want all cookies cleared, this would be the most straightforward way.
const { session } = require('electron');
session.defaultSession.clearStorageData({storages: ['cookies']})
.then(() => {
console.log('All cookies cleared');
})
.catch((error) => {
console.error('Failed to clear cookies: ', error);
});
It supports more complex requests. You can check the documentation here.

Client-side retrieval of Google Contact pictures

I'm fetching google contacts in a webapp using the Google JavaScript API and I'd like to retrieve their pictures.
I'm doing something like this (heavily simplified):
var token; // let's admit this is available already
function getPhotoUrl(entry, cb) {
var link = entry.link.filter(function(link) {
return link.type.indexOf("image") === 0;
}).shift();
if (!link)
return cb(null);
var request = new XMLHttpRequest();
request.open("GET", link.href + "?v=3.0&access_token=" + token, true);
request.responseType = "blob";
request.onload = cb;
request.send();
}
function onContactsLoad(responseText) {
var data = JSON.parse(responseText);
(data.feed.entry || []).forEach(function(entry) {
getPhotoUrl(e, function(a, b, c) {
console.log("pic", a, b, c);
});
});
}
But I'm getting this error both in Chrome and Firefox:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://www.google.com/m8/feeds/photos/media/<user_email>/<some_contact_id>?v=3.0&access_token=<obfuscated>. This can be fixed by moving the resource to the same domain or enabling CORS.
When looking at the response headers from the feeds/photos endpoint, I can see that Access-Control-Allow-Origin: * is not sent, hence the CORS error I get.
Note that Access-Control-Allow-Origin: * is sent when reaching the feeds/contacts endpoint, hence allowing cross-domain requests.
Is this a bug, or did I miss something from their docs?
Assuming you only need the "profile picture", try actually moving the request for that image directly into HTML, by setting a full URL as the src element of an <img> tag (with a ?access_token=<youknowit> at the end).
E.g. using Angular.js
<img ng-src="{{contact.link[1].href + tokenForImages}}" alt="photo" />
With regard to CORS in general, there seem to be quite a few places where accessing the API from JS is not working as expected.
Hope this helps.
Not able to comment yet, hence this answer…
Obviously you have already set up the proper client ID and JavaScript origins in the Google developers console.
It seems that the domain shared contacts API does not work as advertised and only abides by its CORS promise when you request JSONP data (your code indicates that you got your entry data using JSON). For JSON format, the API sets the access-control-allow-origin to * instead of the JavaScript origins you list for your project.
But as of today (2015-06-16), if you try to issue a GET, POST… with a different data type (e.g. atom/xml), the Google API will not set the access-control-allow-origin at all, hence your browser will deny your request to access the data (error 405).
This is clearly a bug, that prevents any programmatic use of the shared contacts API but for simple listing of entries: one can no longer create, update, delete entries nor access photos.
Please correct me if I'm mistaken (I wish I am); please comment or edit if you know the best way to file this bug with Google.
Note, for the sake of completeness, here's the code skeleton I use to access contacts (requires jQuery).
<button id="authorize-button" style="visibility: hidden">Authorize</button>
<script type="text/javascript">
var clientId = 'TAKE-THIS-FROM-CONSOLE.apps.googleusercontent.com',
apiKey = 'TAKE-THAT-FROM-GOOGLE-DEVELOPPERS-CONSOLE',
scopes = 'https://www.google.com/m8/feeds';
// Use a button to handle authentication the first time.
function handleClientLoad () {
gapi.client.setApiKey ( apiKey );
window.setTimeout ( checkAuth, 1 );
}
function checkAuth() {
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true}, handleAuthResult);
}
function handleAuthResult ( authResult ) {
var authorizeButton = document.getElementById ( 'authorize-button' );
if ( authResult && !authResult.error ) {
authorizeButton.style.visibility = 'hidden';
var cif = {
method: 'GET',
url: 'https://www.google.com/m8/feeds/contacts/mydomain.com/full/',
data: {
"access_token": authResult.access_token,
"alt": "json",
"max-results": "10"
},
headers: {
"Gdata-Version": "3.0"
},
xhrFields: {
withCredentials: true
},
dataType: "jsonp"
};
$.ajax ( cif ).done ( function ( result ) {
$ ( '#gcontacts' ).html ( JSON.stringify ( result, null, 3 ) );
} );
} else {
authorizeButton.style.visibility = '';
authorizeButton.onclick = handleAuthClick;
}
}
function handleAuthClick ( event ) {
gapi.auth.authorize ( { client_id: clientId, scope: scopes, immediate: false }, handleAuthResult );
return false;
}
</script>
<script src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
<pre id="gcontacts"></pre>
If you replace cif.data.alt by atom and/or cif.dataType by xml, you get the infamous error 405.
ps: cif is of course related to ajax ;-)

Extjs 4 - How can I get the complete url with params from a currently loaded grid's store?

I have a grid loaded, I want to get the current stores URL which loaded the json data to it , and pass an extra param to it, and load this URL as a pdf, or xls. But how can I get the url?
Get the proxy and ExtraParams:
var url = grid.getStore().getProxy().url;
var params = grid.getStore().getProxy().extraParams;
Then, build the url:
var newUrl = url + '?' + Ext.Object.toQueryString (params);
And the newUrl will be something like this:
your_url_data.json?param1=value1&param2=value2
I don't think that exists a proxy method that do this but you can extend an existing proxy, as follows:
Ext.define ('MyProxy', {
extend: 'Ext.data.proxy.Ajax' ,
buildInternalUrl: function () {
return this.url + '?' + Ext.Object.toQueryString (this.extraParams);
}
});
And then:
var newUrl = grid.getStore().getProxy().buildInternalUrl ();
Result is the same ;)
Here's you can find the doc of proxies: Ajax Proxy
you can get the stores url by yourGrid.getStore().getProxy().url

Ajax In Firefox Plugin

Is there any way to send Ajax requests to server from a Firefox plugin? If yes, how? If no, how do we have client server communication in Firefox plugins?
I want to get some JSON data from server and manipulate the DOM object according to the client input.
I am pretty a beginner in plugin programming.
You can send ajax requests from firefox extension using xmlHTTPRequest, like in any other web application.
From a contentscript you should add the permissions to access cross-domain content, URLs you want to:
"permissions": {
"cross-domain-content": ["http://example.org/", "http://example.com/"]
}
More info in the documentation.
Here's a simple snippet that does XHR request, WITHOUT cookies (due to flag Ci.nsIRequest.LOAD_ANONYMOUS can remove to send with cookies) (MDN :: Info on flags]. Copy this first code block in, then see usage examples below.
var {Cu: utils, Cc: classes, Ci: instances} = Components;
Cu.import('resource://gre/modules/Services.jsm');
function xhrGetPost(url, post_data, cb) {
let xhr = Cc["#mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
let handler = ev => {
evf(m => xhr.removeEventListener(m, handler, !1));
switch (ev.type) {
case 'load':
if (xhr.status == 200) {
cb(xhr.response);
break;
}
default:
Services.prompt.alert(null, 'XHR Error', 'Error Fetching Package: ' + xhr.statusText + ' [' + ev.type + ':' + xhr.status + ']');
break;
}
};
let evf = f => ['load', 'error', 'abort'].forEach(f);
evf(m => xhr.addEventListener(m, handler, false));
xhr.mozBackgroundRequest = true;
if (post_data == undefined) {
post_data = null;
}
if (post_data) {
xhr.open('POST', url, true);
} else {
xhr.open('GET', url, true);
}
xhr.channel.loadFlags |= Ci.nsIRequest.LOAD_ANONYMOUS | Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_PERSISTENT_CACHING;
//xhr.responseType = "arraybuffer"; //dont set it, so it returns string, you dont want arraybuffer. you only want this if your url is to a zip file or some file you want to download and make a nsIArrayBufferInputStream out of it or something
xhr.send(post_data);
}
Example usage of for POST:
var href = 'http://www.bing.com/'
xhrGetPost(href, 'post_data1=blah&post_data2=blah_blah', data => {
Services.prompt.alert(null, 'XHR Success', data);
});
Example usage of for GET:
var href = 'http://www.bing.com/'
xhrGetPost(href, null, data => {
Services.prompt.alert(null, 'XHR Success', data);
});

Resources