Skip to content

Instantly share code, notes, and snippets.

@GuilloOme
Last active March 24, 2023 20:05
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save GuilloOme/2bd651e5154407d2d2165278d5cd7cdb to your computer and use it in GitHub Desktop.
Save GuilloOme/2bd651e5154407d2d2165278d5cd7cdb to your computer and use it in GitHub Desktop.
Puppeteer (v.0.12.0) navigation blocking workaround
(function() {
'use strict';
// keep track of all the opened tab
let tabs = {};
// Get all existing tabs
chrome.tabs.query({}, function(results) {
results.forEach(function(tab) {
tabs[tab.id] = tab;
});
});
// Create tab event listeners
function onUpdatedListener(tabId, changeInfo, tab) {
tabs[tab.id] = tab;
}
function onRemovedListener(tabId) {
delete tabs[tabId];
}
/**
* if the request url differ from the current tab url block it
* @param details
* @return {{redirectUrl: string}}
*/
function onBeforeRequestListener(details) {
let currentTab = tabs[details.tabId];
if (currentTab.url.startsWith('http') && _compareUrls(details.url, currentTab.url)) {
console.warn(`Navigation to ${details.url} blocked.`);
chrome.tabs.executeScript(details.tabId, {file: 'content.js'}, function() {
chrome.tabs.sendMessage(details.tabId, {url: details.url});
});
return {redirectUrl: 'javascript:void(0)'};
}
}
// Subscribe to tab events to track opened tabs
chrome.tabs.onUpdated.addListener(onUpdatedListener);
chrome.tabs.onRemoved.addListener(onRemovedListener);
chrome.webRequest.onBeforeRequest.addListener(onBeforeRequestListener, {
urls: ['<all_urls>'],
types: ['main_frame', 'sub_frame'], // only watching for "frame" type request
}, ['blocking']);
/**
* compare 2 urls based on there href form WITHOUT the hash part
* @param {string} url1
* @param {string} url2
* @return {boolean}
* @private
*/
function _compareUrls(url1, url2) {
let cleanedUrl1 = new URL(url1),
cleanedUrl2 = new URL(url2);
cleanedUrl1.hash = '';
cleanedUrl2.hash = '';
return cleanedUrl1.href !== cleanedUrl2.href;
}
})();
(function() {
'use strict';
// transmitting url received from the background page to the page
chrome.runtime.onMessage.addListener(function(msg) {
window.postMessage({type: 'NavigationBlocked', url: msg.url}, '*');
});
})();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<a href="page1.html">page1 (should be blocked)</a>
<br/><br/>
<a href="javascript:window.location = 'page2.html'">page2 (should be blocked)</a>
<script>
window.onbeforeunload = function() {
console.warn('Page: beforeunload');
};
window.onunload = function() {
console.err('Page : unload');
};
window.addEventListener('message', function(event) {
if (event.data.type && event.data.type === 'NavigationBlocked' && event.data.url) {
console.info('Got url from extension: ' + event.data.url); // since we are in the page, we can retrieve the url the way, we want
}
});
</script>
</body>
</html>
(function() {
'use strict';
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch({
headless: false,
args: {
'--load-extension=/path/to/chrome_extension/',
'--disable-extensions-except=path/to/chrome_extension/',
}
});
const page = await browser.newPage();
await page.goto('https://mypage.lan/example_navigation_away_test_case.html');
await page.click('a');
console.log(await page.content());
await page.screenshot({path: 'screenshot.png'});
await browser.close();
})();
{
"manifest_version": 2,
"name": "Puppeteer workaround - Navigation blocker",
"version": "1.0",
"permissions": [
"webRequest",
"*://*/*",
"webRequestBlocking",
"tabs"
],
"background": {
"persistent": true,
"scripts": [
"background.js"
]
}
}
@GuilloOme
Copy link
Author

GuilloOme commented Nov 10, 2017

Directory structure:

./
|_ chrome_extension/
|    |_ manifest.json (extension declaration)
|    |_ background.js (extension code)
|    |_ content.js (message proxy between the extension and the page)
|
|_ www/
|    |_ example_navigation_away_test_case.html (proof of concept page)
|
|_ index.js (nodeJS proof of concept)

@zema1
Copy link

zema1 commented Jul 18, 2018

Nice job!

@erichocean
Copy link

Puppeteer launch options: --load-extension=./your_ext/ --disable-extensions-except=./your_ext/

@togishub
Copy link

togishub commented Apr 1, 2019

unfortunately with newest Chrome trying to cancel navigation by returning {redirectUrl: 'javascript:void(0)'} from onBeforeRequestListener results in Chrome error: ERR_UNSAFE_REDIRECT (This site can’t be reached)

any thoughts for a new solution?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment