chrome.cookies.getAll returns an empty array - javascript

I'm working on a simple chrome extension that will delete all cookies from a domain with one click but for some reason, it's not working. When I try to get all the cookies from the domain, it returns an empty array. What am I doing wrong?
Here's the js script:
$("#fixTheCookiesButton").click(() => {
// delete the cookies
chrome.cookies.getAll({domain: "https://www.youtube.com"}, (cookies) => {
console.log("deleting " + cookies.length + " cookies")
for(var i = 0; i < cookies.length; i++){
console.log(i + " deleted")
chrome.cookies.remove({
url: "https://www.youtube.com" + cookies[i].path,
name: cookies[i].name
})
}
// some other stuff that isn't relevant here
}
and here's my manifest:
{
"manifest_version": 2,
"name": "FixYT",
"version": "1.0",
"description": "Fixes that YT cookie bug with one click",
"browser_action": {
"default_title": "FixYT",
"default_popup": "popup.html"
},
"permissions": [
"cookies",
"https://www.youtube.com/",
"*://www.youtube.com/",
"tabs",
"*://*/"
]
}
I've tried looking around the internet but I can't find any solutions to this.

you should call this code block in background.js
chrome.cookies.getAll({
domain: ".youtube.com"
}, function (cookies) {
for (var i = 0; i < cookies.length; i++) {
console.log(cookies[i] + "deleted");
chrome.cookies.remove({
url: "https://" + cookies[i].domain + cookies[i].path,
name: cookies[i].name
});
}
});

As isa says, chrome.cookies is only defined in background.js
Add to manifest so we have access to chrome.cookies in background.js
 
 "permissions": [
     ...
      "cookies",
    ],
background.js
...
chrome.cookies.getAll({
}, function (theCookies) {
cookies = theCookies
console.log(cookies)
});
Sending Cookies from background.js to other views
(Not required, but still useful)
Add to panel.js to search for cookies. [This will fire when you open your extension ie (puzzle piece icon) -> click on your extension]
chrome.runtime.sendMessage({ command: "GetCookies"},
function(response) {
console.log("I received cookies!")
console.log(response)
}
);
Add to background.js logic to get cookies from the browser and check for known cookies
chrome.runtime.onMessage.addListener(function (message, sender, callback) {
if (message.command === 'GetCookies') {
checkKnownCookies()
}
});
let cookies = [] // Hold IDs of recognized cookies
function checkKnownCookies() {
chrome.cookies.getAll({
}, function (theCookies) {
cookies = theCookies
console.log(cookies)
callback(theCookies)
});
}
 
https://developer.chrome.com/docs/extensions/reference/cookies/#method-getAll
To view console for background.js go to (puzzle piece icon) -> manage extensions and click on the href link to background.html for your extension

Both permissions and host_permissions are required.
"permissions": [
"cookies",
"tabs"
],
"host_permissions": ["<all_urls>"],

Related

Javascript Browser WebExtension API Manifest v3 - Service Worker and chrome.storage.local API issue

I'm implementing a small extension for Copy as cURL feature (as done by the Network tab of DevTools) and I would like to use Manifest v3. According to the documentation and to the contribution of the community, Service Worker at a certain time stops to live so some variables cannot retrieve the needed information from the active tab.
For managing this, I'm using chrome.storage.local.set and .get functions in order to keep the needed information also after the Service Worker stops to live. When I run the extension test, I don't receive any error, but, despite I retrieve the stored variables by the chrome.storage API, sometimes I continue to not retrieve the values anymore also when the Service Worker should be alive. For example:
when I connect to a website, I can retrieve and copy the correct data also in 1 min, then, if I continue to Copy (without refreshing the page), I don't get the parameters (i.e., GET headers).
sometimes, if I open a new tab, insert an address and quickly press Copy as cURL, of my extension, headers are not copied, and I need to refresh the page (not by clicking refresh button of browser but click on URL then ENTER) for getting them.
Maybe the issue is not related to the Time-to-live of the Service Worker because I can keep a page opened for a lot of minutes and it gives me the right parameters. I don't know where my approach is failing. The code of this small implementation is the following:
background.js
"use strict";
/*
Called when the item has been created, or when creation failed due to an error.
We'll just log success/failure here.
*/
function onCreated() {
if (chrome.runtime.lastError) {
console.log(`Error: ${chrome.runtime.lastError}`);
} else {
console.log("Item created successfully");
}
}
/*
Called when the item has been removed.
We'll just log success here.
*/
function onRemoved() {
console.log("Item removed successfully");
}
/*
Called when there was an error.
We'll just log the error here.
*/
function onError(error) {
console.log(`Error: ${error}`);
}
/*
Create all the context menu items.
*/
chrome.contextMenus.create({
id: "tools-copy",
//title: chrome.i18n.getMessage("menuItemToolsCopy"),
title: "Copy",
contexts: ["all"],
}, onCreated);
chrome.contextMenus.create({
id: "tools-copy-curl",
parentId: "tools-copy",
//title: chrome.i18n.getMessage("menuItemToolsCopyAsFFUF"),
title: "Copy as cURL",
contexts: ["all"],
}, onCreated);
const tabData = {};
const getProp = (obj, key) => (obj[key] || (obj[key] = {}));
const encodeBody = body => {
var data = '';
// Read key
for (var key in body.formData) { //body is a JSON object
data += `${key}=${body.formData[key]}&`;
}
data = data.replace(/.$/,"");
var body_data = `'${data}'`;
return body_data;
}
const FILTER = {
types: ['main_frame', 'sub_frame'],
urls: ['<all_urls>'],
};
const TOOLS = {
CURL: 'tools-copy-curl',
};
chrome.webRequest.onBeforeRequest.addListener(e => {
getProp(getProp(tabData, e.tabId), e.frameId).body = e.requestBody;
chrome.storage.local.set({tabData: tabData}, function() {
console.log('HTTP request saved');
});
}, FILTER, ['requestBody']);
chrome.webRequest.onBeforeSendHeaders.addListener(e => {
getProp(getProp(tabData, e.tabId), e.frameId).headers = e.requestHeaders;
chrome.storage.local.set({tabData: tabData}, function() {
console.log('HTTP request saved');
});
}, FILTER, ['requestHeaders']);
chrome.tabs.onRemoved.addListener(tabId => delete tabData[tabId]);
chrome.tabs.onReplaced.addListener((addId, delId) => delete tabData[delId]);
chrome.contextMenus.onClicked.addListener((info, tab) => {
chrome.storage.local.get(["tabData"], function(items) {
const data = items.tabData[tab.id]?.[info.frameId || 0] || {};
if (info.menuItemId === TOOLS.CURL) {
var txt_clip = `curl -u '${info.frameUrl || tab.url}'` +
(data.headers?.map(h => ` -H '${h.name}: ${h.value}'`).join('') || '') +
(data.body? ' --data_raw ' + encodeBody(data.body) : '');
}
chrome.tabs.sendMessage(tab.id,
{
message: "copyText",
textToCopy: txt_clip
}, function(response) {})
});
});
content.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.message === "copyText") {
navigator.clipboard.writeText(request.textToCopy);
sendResponse({status: true});
}
}
);
manifest.json
{
"manifest_version": 3,
"name": "CopyAsCURL",
"description": "Copy as cURL test example.",
"version": "1.0",
"default_locale": "en",
"background": {
"service_worker": "background.js"
},
"permissions": [
"contextMenus",
"activeTab",
"cookies",
"webRequest",
"tabs",
"clipboardWrite",
"storage"
],
"host_permissions": [
"<all_urls>"
],
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": ["content.js"]
}
],
"icons": {
"16": "icons/menu-16.png",
"32": "icons/menu-32.png",
"48": "icons/menu-48.png"
}
}
I want also to thank #wOxxOm for the support on similar topic.

Problems with asynchronous calls in chrome extension

I had this idea for a new chrome extension:
It should create a linking QR code for the currently open website, displayed in the popup.html which can be easily scanned with the smartphone. If you watch a video on YouTube, the current time of the video should be also embedded in the QR code, which makes it possible to continue watching the video directly in the YouTube app on the smartphone.
So far so good. But now I have the following problem:
This extension works fine on all websites. Only on Youtube there seems to be a problem with the asynchrony of the onmessage listener and the sending of the message to the contentScript (requesting the current time of the viewed YouTube video).
In the debugging console I get the following errors:
Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.
... getting this after trying to execute line 7 of background.js
Error handling response: TypeError: Cannot read property 'videoTime' of undefined
at chrome-extension://...../background.js:8:70
... getting this after trying to execute line 8 of background.js
popup.js
$(function() {
chrome.runtime.sendMessage({text: 'sendURL'}, function(response) {
$('#qr-code').attr('src', getQRCodeImgURL(response.url));
});
});
function getQRCodeImgURL(url) {
var qrCodeURL = new URL('http://api.qrserver.com/v1/create-qr-code/');
qrCodeURL.searchParams.set('data', encodeURI(url));
qrCodeURL.searchParams.set('size', '200x200');
return qrCodeURL;
}
background.js
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
if (message.text == 'sendURL') {
chrome.tabs.query({active: true, /* lastFocusedWindow: true */}, function (tabs) {
var currentURL = new URL(tabs[0].url);
if (currentURL.href.indexOf('youtube.com/watch?v=') >= 0) { // if current website is youtube
chrome.tabs.sendMessage(tabs[0].id, { text: 'sendVideoTime' }, function (response) {
const ytVideoTime = timeStringToSeconds(response.videoTime);
var ytURL = new URL('https://youtu.be/');
ytURL.pathname = '/' + currentURL.searchParams.get('v');
ytURL.searchParams.set('t', ytVideoTime);
currentURL = ytURL;
sendResponse({ url: currentURL.href });
});
} else {
sendResponse({ url: currentURL.href });
}
});
}
return true;
});
function timeStringToSeconds(timeString) {
var seconds = 0;
var hms = timeString.split(':');
if (hms.length == 3) {
seconds = parseInt(hms[0])/* hours */ * 60 /* minutes per hour */ * 60 /* seconds per minute */;
hms.shift(); /* remove first element, for accessing first element in next step (also if hms doesnt is in this hh:mm:ss format) */
}
return seconds + (parseInt(hms[0]) * 60) /* seconds per minute */ + parseInt(hms[1]) /* seconds */;
}
contentScript.js
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if (message.text == 'sendVideoTime') {
const time = document.evaluate('//*[#id="movie_player"]/div[27]/div[2]/div[1]/div[1]/span[1]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.textContent;
sendResponse({videoTime: time});
}
return true;
});
manifest.json
{
"manifest_version": 2,
"name": "URL-QR-Code-Creator",
"version": "1.0",
"description": "This extension creates a linking QR code for the currently open website, which can be easily scanned with the smartphone. If you watch a video on the YouTube website, the current time of the video is also embedded in the QR code, which makes it possible to continue watching the video directly in the YouTube app on the smartphone.",
"icons": {
"16": "images/qr-code-16px.png",
"32": "images/qr-code-32px.png",
"48": "images/qr-code-48px.png",
"64": "images/qr-code-64px.png",
"128": "images/qr-code-128px.png"
},
"browser_action": {
"default_icon": {
"16": "images/qr-code-16px.png",
"32": "images/qr-code-32px.png",
"48": "images/qr-code-48px.png",
"64": "images/qr-code-64px.png",
"128": "images/qr-code-128px.png"
},
"default_title": "show QR-Code",
"default_popup": "popup.html"
},
"background": {
"scripts": [
"background.js"
],
"persistant": false
},
"content_scripts": [
{
"matches": ["*://www.youtube.com/watch?v=*"],
"js": ["contentScript.js"]
}
],
"permissions": [
"activeTab",
"tabs"
]
}
I did it!
At first I said goodbye to the idea of regulating access to the youtube DOM via an extra content script.
So I deleted contentScript.js and deleted it from manifest.json.
Now I simply accessed the DOM using the chrome.tabs.executeScript method in the background.js file and got the result using the callback function. Quite simply - without having to send messages around all the time.

chrome extension not work after load new data

I developed a chrome extension which generates a custom message for me from skype on clicking it. It works fine on page load and when I scroll down and load more connection to send message extension stop work on it.
{
"name": "Page Redder",
"description": "Make the current page red",
"version": "2.0",
"content_scripts": [
{
"run_at" :"document_end",
"matches": ["<all_urls>"],
"js": ["jquery.js","script.js"]
}
],
"permissions": [
"activeTab"
],
"background": {
"scripts": ["background.js"],
"persistent": true
},
"browser_action": {
"default_title": "Make this page red"
},
"manifest_version": 2
}
jquery file
$(document).ready(function(){
$('.mn-person-card__person-btn-ext').click(function(){
var name = $(this).attr('aria-label');
name = name.replace("Send message to ","");
var dummyContent = "Hello " + name + ", \n\nThanks for staying connected with me on LinkedIn.";
$('body').append("<textarea id='absdfjalskjdf'></textarea>");
document.getElementById('absdfjalskjdf').innerHTML = dummyContent;
var dummy =$('#absdfjalskjdf').select()
document.execCommand("Copy");
$('#absdfjalskjdf').remove();
});
});
$(document).on('change', function(){
$('.mn-person-card__person-btn-ext').click(function(){
alert("asldfkjaldfj");
var name = $(this).attr('aria-label');
name = name.replace("Send message to ","");
var dummyContent = "Hello " + name + ", \n\nThanks for staying connected with me on LinkedIn.";
$('body').append("<textarea id='absdfjalskjdf'></textarea>");
document.getElementById('absdfjalskjdf').innerHTML = dummyContent;
var dummy =$('#absdfjalskjdf').select()
document.execCommand("Copy");
$('#absdfjalskjdf').remove();
});
});
When I open all my connection, first loaded connections are work successfully but when load some more connections that time it stop to work. Please help me to make it possible.

Creating cookies from background page

I have a background script in my extension that creates a context menu item and handles it. When it is clicked, a cookie is created with specific details. Here is the source for that file:
script.js
function createC() {
var x = 1;
var y = 2;
//Create Cookie
document.cookie = document.URL + "=" + " " + x + " " + y + " ; " + 4102444799;
console.log("Cookie Created.");
}
chrome.contextMenus.create({
title: "Create Cookie",
contexts:["all"],
onclick: createC,
});
Obviously the variables used in it are for testing. When I run document.cookie; in the console, the cookie does not appear. I have tried using the chrome.cookies API and had the same issue.
Does the cookie not appear because it is created in the background script? I am trying to set it on the current tab the user is on, not the background page itself.
manifest.json
{
"manifest_version": 2,
"name": "MyExtension",
"description": "Do stuff",
"version": "0.1",
"icons": { "16": "icon.png",
"48": "icon.png",
"128": "icon.png" },
"options_page": "options.html",
"permissions": [
"tabs", "<all_urls>", "contextMenus", "cookies"
],
"background": {
"scripts": ["script.js"]
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["nav.js"]
}
]
}
In background script, 'document' is not for the current page, but for the extension background page(chrome-extension://[your extension id]/bacground.html). So, you can't use 'document.cookie', you need to try chrome.cookies.get like this:
/**
* Create cookie for the special page
* #param {Object<key, value>} detail
* #param {Function=} opt_callback
*/
function createCookie(detail, opt_callback) {
chrome.cookies.set(detail, opt_callback);
}
You need to use javascript code in specific tab if you want to use the document the current page instead of background.html.
This can be done by function executeScript, your syntax is :
chrome.tabs.executeScript( tabId, details, callback )
chrome.tabs.executeScript( MyTabIdNumberMandatoryInYourCase, MyScriptCodeInLineOrUrl, MyCallbackOptional )
tabId matches the ID of the active tab page, background.js file is executed under the main background.html, then you need to pass the correct ID if you do not pass it, and hopefully it will execute the background.html as the active tab.
All WebRequest events, has a variable called details and she carries a tabid value, and you access it via details.tabId, below is a code that I use in one of my extensions already created.
var onCompletedExecuteScriptDetails = {
// You can run all the code in the inline form,
// rather than using the parameter "file", use the "code" parameter, but is very ugly,
// is much more elegant to use the "file" mode
// my-script.js is a file with code to create cookie
file : "my-script.js"
};
var onCompletedExecuteScript = function ( details ) {
chrome.tabs.executeScript( details.tabId, onCompletedExecuteScriptDetails );
};
var onCompletedCallback = function ( details ) {
document.addEventListener( 'DOMContentLoaded', onCompletedExecuteScript( details ) );
};
var onCompletedFilter = {
urls : [
"http://*/*",
"https://*/*"
]
};
chrome.webRequest.onCompleted.addListener( onCompletedCallback, onCompletedFilter, onCompletedInfo );
executeScript
I ended up using:
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if (changeInfo.url != null) {
url = changeInfo.url;
}
});
This is what I ended up doing.
In manifest.json:
"permissions": [
"cookies",
"*://*.target_website.com/",
"*://*/_generated_background_page.html"
]
In background.js
chrome.cookies.set({
"name": "cookie's name",
"url": "the URL you want to apply the cookies to",
"value": "cookie's value"
}, function(cookie) {
if (chrome.extension.lastError) {
console.log(chrome.extension.lastError);
}
if (chrome.runtime.lastError) {
console.log(chrome.runtime.lastError);
}
});

Access-Control-Allow-Origin not checking in chrome extension

As you know, when send $.ajax(..) request to another domain (cross-domain), most browser throw exception like:
XMLHttpRequest cannot load http://mysite.com/test.php. Origin
http://127.0.0.1:8888 is not allowed by Access-Control-Allow-Origin.
I am creating chrome extension and it should send a request to my website. First , i expected to see above message,too. But i confused when i see it worked fine.
First, It’s seem good, it’s working and i have what i want. But it can be horrible. Every one can use such way (only a simple script) to attack my site and grab its data.
Of course, grabbing could be happen in other ways, too.
I am new in api programing and chrome extension. Do anyone may show me the way?
manifest.json
{
"manifest_version": 2,
"name": "MyTestExtension",
"description": "this extension is for test",
"version": "1.0",
"icons": {
"128": "icon.png"
},
"browser_action": {
"default_icon": "icon.png"
},
"permissions": [
"tabs" ,
"*://*/*"
],
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["jquery-1.7.2.min.js","content_script.js"],
"run_at": "document_end"
}
]
}
content_script.js
$(document).ready(function(){
$('html').mouseup(function() {
var selectedText = getSelectedText();
if(selectedText > ''){
my_syncTest(selectedText) // here : selected test send to my site
}
});
function getSelectedText() {
if (window.getSelection) {
var selection = window.getSelection().toString();
if(selection.trim() > ''){
return selection;
}
} else if (document.selection) {
var selection = document.selection.createRange().text;
if(selection.trim() > ''){
return selection;
}
}
return '';
} });
function my_syncTest(word){
var qs = 'word='+word+'&header=555&simwords=1';
$.ajax(
{
type: "POST",
url: 'http://mysite.com/test.php',
dataType: 'json',
data : qs,
success:function(res){
console.log(res.success +" - "+ res.idWord + " - " + res.header +" - " + res.meaning);
}});
}
XMLHttpRequests from your extension work because you defined these permissions in the manifest:
"permissions": [
"*://*/*"
]
When a user installs your extension, he is informed that this extension can access his data on all sites. I prefer only including the exact site you need instead of wildcards.
http://developer.chrome.com/extensions/xhr.html
This mechanism is to protect the user, not to protect your site. If you don't want everybody to use your API, use API-keys, or look into oAuth:
http://en.wikipedia.org/wiki/OAuth
If you want to learn more about cross origin requests:
http://en.wikipedia.org/wiki/Cross-origin_resource_sharing
https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS

Categories