I'm trying to write a chrome extension which intercepts network traffic and modify the data.
I would appreciate if someone can tell me exactly which API I should use for this and where I can find the documentation.
Make use of the webRequest API and have a look at their events.
Create a manifest with permissions activeTab to get permissions for the current tab on which you are on, and the url pattern you wish the extension to be enabled for. The webRequestBlocking permission needs to be set specifically for blocking and modifying traffic.
manifest.json
{
"manifest_version": 2,
"name": "network intercepter",
"description": "intercept/modify/block data",
"version": "1.0",
"background": {
"scripts": ["background.js"]
},
"host_permissions": [
"https://*.google.com/*"
],
"permissions": [
"activeTab",
"webRequest",
"webRequestBlocking"
]
}
Create a background script and start adding webRequest listener based on which actions you want to perform. This was useful for me when making those choices.
background.js
var onBeforeSendHeadersListener = function(details) {
// view request + headers to be send
console.log(details);
// block XMLHttpRequests by returning object with key "cancel"
if (details.type == "xmlhttprequest") {
return {
cancel: true
};
}
// modify the user agent of all script resources by changing the requestHeaders and then return an object with key "requestHeaders"
if (details.type == "script") {
for (var i = 0; i < details.requestHeaders.length; i++) {
if (details.requestHeaders[i].name == "User-Agent") {
details.requestHeaders[i].value = "I'm not a bot";
}
}
return {
"requestHeaders": details.requestHeaders
};
}
}
var onBeforeRequestListener = function(details) {
// all images will now be loaded from this location instead
// CAREFUL! CROSS ORIGIN REQUESTS WILL NOT BE BLOCKED WITH CHROME EXTENSIONS
if (details.type == "image") {
return {
"redirectUrl": "https://foo.bar/image.jpg"
};
}
}
chrome.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeadersListener, {
urls: ["https://*.google.com/*"]
}, ["requestHeaders", "blocking"]);
chrome.webRequest.onBeforeRequest.addListener(onBeforeRequestListener, {
urls: ["https://*.google.com/*"]
}, ["requestBody", "blocking"]);
Visit chrome://extensions and open the background page, and go to its console. Then visit https://google.com normally, you will see that all images are changed to their new location, the XHR's are blocked, and the script resources have their User Agent changed, and in the background console you will find the requests that were made.
Related
I'm trying to use the Microsoft Graph API to write calendar events within my company.
First of all let me give you a little bit of context.
I'm building a node API that uses Microsoft Graph to write calendar events, so I configured my application inside the Azure Active Directory with the following application permission
I granted administrator consent as you can see from the picture.
I was also able to get the access token using msal-node
const graphToken = async () => {
const azureConfig = {
auth: {
clientId: process.env.CLIENT_ID,
authority: `https://login.microsoftonline.com/${process.env.TENANT_ID}`,
clientSecret: process.env.CLIENT_SECRET,
},
}
const tokenRequest = {
scopes: [process.env.GRAPH_ENDPOINT + '/.default'],
}
const cca = new msal.ConfidentialClientApplication(azureConfig)
const authRespose = await cca.acquireTokenByClientCredential(tokenRequest)
if (authRespose) {
return authRespose.accessToken
}
return null
}
The only thing that sounds me a little odd, is the scope set to [process.env.GRAPH_ENDPOINT + '/.default'] I tried to change it ex. [process.env.GRAPH_ENDPOINT + '/Calendar.ReadWrite'] but it fires an excepion.
The next thing I'm able to do is retrive all calendars a user have right to write to, using the following Graph endpoint:
https://graph.microsoft.com/v1.0/users/user#example.com/calendars
Now the issue, when I try to do a POST request to write a calendar event for example
POST https://graph.microsoft.com/v1.0/users/{userId}/calendars/{calendarId}/events
{
"subject": "Test",
"body": {
"contentType": "HTML",
"content": "Test"
},
"start": {
"dateTime": "2022-11-09T16:00:00",
"timeZone": "Europe/Rome"
},
"end": {
"dateTime": "2022-11-09T17:00:00",
"timeZone": "Europe/Rome"
}
}
Note that calendarId is one of the id's from the previous call
(Not the default calendar of userId)
I got a 403 Forbidden with the following response
{
"error": {
"code": "ErrorAccessDenied",
"message": "Access is denied. Check credentials and try again."
}
}
I also decoded my token to see if I get some info on the root cause of the 403 error, I found this:
...
"roles": [
"Calendars.Read",
"User.Read.All",
"Calendars.ReadWrite"
],
...
It seems correct to me.
I don't get if it is a scope issue, an authentication issue or something I'm missing, can someone pinpoint me in the right direction?
Thanks in advance
Basically it was my fault.
I messed up with calendar permissions and my test user had a reviewer permission instead of an author one on the calendar I had to write to
once I was able to identify this issue and change the permission the call response was what expected.
I leave this answer as a reference for anyone that encounter this issue
Thanks anyway
I have developed an extension and using Chrome API, which sends notification every 20 secs from background script
manifest.json
{
"name": "Test",
"description": "Test",
"manifest_version": 2,
"version": "0.1",
"chrome_url_overrides" : {
"newtab": "register.html"
},
"background": {
"scripts": ["background.js"]
},
"permissions": ["idle", "tabs", "gcm", "storage", "notifications"],
"icons": { "128": "gcm_128.png" }
}
background.js //sends notification
function messageReceived(message) {
var messageString = '';
if(message) messageString = message;
var nid = getNotificationId();
messageString = messageString + nid;
// Pop up a notification to show the GCM message.
chrome.notifications.create(nid, {
title: 'Kukdu Kuuu',
iconUrl: 'gcm_128.png',
type: 'basic',
message: messageString
}, function() {});
}
// Returns a new notification ID used in the notification.
function getNotificationId() {
var id = Math.floor(Math.random() * 9007199254740992) + 1;
return id.toString();
}
setInterval(function() {
console.log('running - ');
messageReceived('test notification ');
}, 20000);
It shows a notification when I am not on Chrome browser i.e when I am out of focus. But I don't receive notification when I am working on chrome.
When I run API, chrome.notifications.getAll(), I get the entire queue of IDs.
But, notifications are not getting displayed immediately on my system. What could be the problem? However, it works well on the windows machine.
This is an open issue in chrome.
Here is the link,
https://bugs.chromium.org/p/chromium/issues/detail?id=583746#
Important comments & summary,
This is definitely intentional but is is also a questionable decision.
Pro: * Won't interrupt immersive content such as movies with a
notification.
Con: * People use full screen to just browse as well,
esp. on Mac with the new fullscreen mode.
( Comment by dewittj#chromium.org )
And current behaviour of pushnotifications,
It queues received notification while in full-screen mode.
It shows all the notifications when user exits fullscreen mode or switch to some other app or window.
If the user exits the browser, the notifications is displayed on next browser restart.
While using the classic Azure Mobile services, you used to get a key along with a URL for your Mobile Service app. This key was also used to explore the APIs on your backend site & was used as a password.
With new Azure App services all you need to instntiate the mobile service client is the URL like below
private static readonly MobileServiceClient MobileService = new MobileServiceClient("https://thecityapp.club");
There is no key *a second parameter that was available with Azure Mobile services. What is now used as password to explore the APIs on the web?
Supreet,
With App Services/Mobile Apps, the application key is no longer used/required, that is why it is no longer available on the portal. You can instantiate the client with the above code and start consuming the service APIs without that information.
For authentication, please refer to this documentation: https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-windows-store-dotnet-get-started-users/
I hope this helps.
You can implement Application Key for Azure Mobile App if you want.
You can set an application key for your Azure Mobile App like Azure Mobile Services.
1. Open Application Settings on Azure Mobile Application
2. Scroll down to App Settings Add these two lines.
| zumo-api-key | TYPE YOUR API KEY |
| MS_SkipVersionCheck | True |
3. Then click Save
4. Open App Service Editor
5. Create a file on your main folder wwwroot
6. Name your file as validateApiKey.js
// ----------------------------------------------------------------------------
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
// ----------------------------------------------------------------------------
module.exports = function (req, res, next) {
// Validate zumo-api-key header against environment variable.
// The header could also be validated against config setting, etc
var apiKey = process.env['zumo-api-key'];
if (apiKey && req.get('zumo-api-key') != apiKey)
return res.status(401).send('This operation requires a valid api key');
else
return next();
}
6. Update your API script as,
[sampleAPI.js]
var validateApiKey = require('../validateApiKey');
module.exports = {
"get": [validateApiKey, function(request, response, next)
{
response.send(
{
message: "post"
});
}],
"post": [validateApiKey, function(request, response, next)
{
response.send(
{
message: "post"
});
}]
};
[sampleAPI.json]
{
"get": {
"access": "anonymous"
},
"post": {
"access": "anonymous"
},
"put": {
"access": "anonymous"
},
"patch": {
"access": "anonymous"
},
"delete": {
"access": "anonymous"
}
}
Do not forget to change permissions to "Anonymous"
6. Update your Table script as,
[sampleTable.js]
var azureMobileApps = require('azure-mobile-apps'),
validateApiKey = require('../validateApiKey');
// Create a new table definition
var table = azureMobileApps.table();
// Access should be anonymous so that unauthenticated users are not rejected
// before our custom validateApiKey middleware runs.
table.access = 'anonymous';
// validate api key header prior to execution of any table operation
table.use(validateApiKey, table.execute);
// to require api key authentication for only one operation (in this case insert)
// instead of table.use(validateApiKey, table.execute) use:
// table.insert.use(validateApiKey, table.operation);
module.exports = table;
[sampleTable.json]
{
"softDelete" : true,
"autoIncrement": false,
"insert": {
"access": "anonymous"
},
"update": {
"access": "anonymous"
},
"delete": {
"access": "anonymous"
},
"read": {
"access": "anonymous"
},
"undelete": {
"access": "anonymous"
}
}
Do not forget to change permissions to "Anonymous"
7. Done!
Do not forget to add header while calling Azure Mobile/Web App.
Also, you can see more from this repository on Github.
https://github.com/thisisfatih/applicationKeyAzure/
I want to include facebook login functionality in my chrome extension. I have included
connect.facebook.net/en_US/all.js file in popup.html. But not working.
i m using code
window.fbAsyncInit = function() {
// init the FB JS SDK
FB.init({
appId: 'APP_ID', // App ID from the App Dashboard
//channelUrl : '//www.example.com/', // Channel File for x-domain communication
status: true, // check the login status upon init?
cookie: true, // set sessions cookies to allow your server to access the session?
xfbml: true // parse XFBML tags on this page?
});
// Additional initialization code such as adding Event Listeners goes here
console.log(FB);
};
// Load the SDK's source Asynchronously
(function(d, debug) {
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {
return;
}
js = d.createElement('script');
js.id = id;
js.async = true;
js.src = "http://connect.facebook.net/en_US/all" + (debug ? "/debug" : "") + ".js";
ref.parentNode.insertBefore(js, ref);
}(document, /*debug*/false));
but getting error
Refused to load the script 'http://connect.facebook.net/en_US/all.js' because it violates the following Content Security Policy directive: "script-src 'self' chrome-extension-resource:".
I use the following code and it works, without damaging the CSP
function loginfacebook()
{
chrome.windows.create(
{
'url': "https://www.facebook.com/dialog/oauth?client_id=yourclientid&redirect_uri=https://www.facebook.com/connect/login_success.html&scope=email&response_type=token"
}, null);
chrome.tabs.query({active:true}, function(tabs){
tabid = tabs[0].id;
chrome.tabs.onUpdated.addListener(function(tabid, tab)
{
var cadena = tab.url;
if (cadena != null)
{
var resultado = cadena.match(/[\\?&#]access_token=([^&#])*/i);
}
if (resultado != null)
{
token = resultado[0];
token = token.substring(14);
storagetoken(token);
};
});
As the error message says, the Facebook script isn't CSP-compliant. I haven't looked at that script, but if you can't modify it and fix the CSP issues, you have a couple options in general for dealing with such scripts:
Put it in a sandboxed iframe.
Put the script in a <webview>.
Unfortunately, the point of that Facebook script is likely to set a cookie after FB authentication, and that cookie would stay in either the iframe or the webview, so neither of these approaches will end up with the required cookie in your main app. You'll have to figure out a way to transmit the product (cookie) of the FB login operation to your app, likely through postMessage. If you do that legwork and succeed, please post your results somewhere, such as in a sample app on GitHub.
My extensions makes excessive use of chrome.tabs.captureVisibleTab(), however if the user is browsing in pages that I don't have permissions on the call fails with the following error message in the console:
Error during tabs.captureVisibleTab: Cannot access contents of url "chrome://settings/extensions#". Extension manifest must request permission to access this host.
While this doesn't interfere with the normal flow of my extension, I was wondering if these is a way to check for permissions before calling chrome.tabs.captureVisibleTab() to prevent my extension from seeming unprofessional
Did you try handling the error with a try...catch statement? Something like this:
try {
// If any error rises here
chrome.tabs.captureVisibleTab();
} catch(e) {
// Supress the error and go here
}
Just get extension's manifest info and then:
for(var i = 0, permissions = {}; i < chrome.manifest.permissions.length; i++){
// map array to object for later use
permissions[chrome.manifest.permissions[i]] = true;
}
if(permissions.hasOwnProperty('tabs')){
// capture
}
UPDATE:
Recently (dev channel) Chrome devs added new powerfull API - chrome.permissions (docs). So you can check if your extension have particular permission by:
chrome.permissions.contains({
permissions: ['tabs'],
origins: ['http://www.google.com/']
}, function(result) {
if (result) {
// The extension has the permissions.
} else {
// The extension doesn't have the permissions.
}
});