Chrome onBeforeSendHeaders not catching FTP request - google-chrome-extension

I'm developing a chrome extension which will add Authorization headers to the requests.
For this I used onBeforeSendHeaders, but unfortunately it isn't working for FTP requests. I have given the permission in manifest and also in background
Manifest permissions says:
"permissions": [
"webRequest",
"webRequestBlocking",
"webNavigation",
"tabs",
"cookies",
"ftp://*/*",
"*://*/*"
]
and I used onBeforeSendHeaders like this:
chrome.webRequest.onBeforeSendHeaders.addListener(
function(details) {
if(details.url == "my_url"){
details.requestHeaders.push({'name':'Authorization','value':'my_value'});
return { requestHeaders: details.requestHeaders };
}
},
{urls: ['<all_urls>','ftp://*/*']},
[ 'blocking', 'requestHeaders']
);
callback(true);
}
And also if I fail to open FTP in Chrome; is there any other way, where I could open FTP in terminal or putty using a single command (something like ssh user#host -pw pass)?

onAuthRequired is the solution to it, and worked for me:
var target = "ftp://ftpurl/";
var myCredentials = {
username: "username",
password: "pass"
};
var pendingRequests = [];
// A request has completed.
// We can stop worrying about it.
function completed(requestDetails) {
console.log("completed: " + requestDetails.requestId);
var index = pendingRequests.indexOf(requestDetails.requestId);
if (index > -1) {
pendingRequests.splice(index, 1);
}
}
function provideCredentialsSync(requestDetails) {
// If we have seen this request before, then
// assume our credentials were bad, and give up.
if (pendingRequests.indexOf(requestDetails.requestId) != -1) {
console.log("bad credentials for: " + requestDetails.requestId);
return {cancel:true};
}
pendingRequests.push(requestDetails.requestId);
console.log("providing credentials for: " + requestDetails.requestId);
return {authCredentials: myCredentials};
}
chrome.webRequest.onAuthRequired.addListener(
provideCredentialsSync,
{urls: [target]},
["blocking"]
);
chrome.webRequest.onCompleted.addListener(
completed,
{urls: [target]}
);
chrome.webRequest.onErrorOccurred.addListener(
completed,
{urls: [target]}
);
}

Related

Chrome.identity.getAuthToken not showing Google user list

content.js This is the content page for chrome extension
document.getElementById("signIn").addEventListener("click", function(){
chrome.runtime.sendMessage({task:"switchUser", user: current_user},function(response){
});
});
background.js This is the background page for chrome extension
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse){
if(request.task == "switchUser"){
function getToken(){
chrome.identity.getAuthToken({ interactive: true }, function(token) {
sendResponse(token);
});
}
chrome.identity.removeCachedAuthToken({ token:
currentSessionAccessToken }, getToken);
}
return true;
});
Previous OAuth token is successfully removed but when generating a new one using getAuthToken, the user selection list is not shown. However, I have set interactive to true. What am I missing?
You need to revoke the token first and then remove from cache. Please find the code below for background.js page.
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse){
if(request.task == "switchUser"){
function getToken(){
chrome.identity.getAuthToken({ interactive: true }, function(token) {
sendResponse(token);
});
}
var xmlHttp = new XMLHttpRequest();
xmlHttp.open('GET', 'https://accounts.google.com/o/oauth2/revoke?token=' + currentSessionAccessToken); //revoke the token calling this url.
xmlHttp.onload = function() {
chrome.identity.removeCachedAuthToken({ token: currentSessionAccessToken }, getToken); //after token is revoked, remove it from cache as well.
}
xmlHttp.onerror = function(){
};
xmlHttp.send();
}
return true;
});

Why does my background page become unavailable?

I've had a long-running Chrome Extension where I'm used to always have access to the background.js page for viewing console, trouble-shooting etc.
I'm implementing Firebase login and have made some changes...and now, after I log into my app, the 'background page' becomes the html of the current popup.
Manifest below...
When you reload or first install the Extension I see what I'm used to...and can click on the link to view the "_generated_background_page.html". Buttons in the popup correctly communicate (via messaging) to run functions in background.js.
However, after logging in, the new popup (I redirect to a new popup for logged in users) replaces the background page (my words) and (most importantly) I can't access the background page anymore. Messaging doesn't have any effect and I can't "see" the console / inspect the background.js page.
In the past I've seen a background page AND another, open page and can inspect them both.
Any thoughts on how I have succeeded in painting myself into a corner? It's as if I'm closing the background.js file.
Manifest:
{
"manifest_version": 2,
"name": "Annotate PRO for Chrome",
"short_name": "Annotate PRO",
"description": "Right-click access to a pre-written library of comments. Write it once, to perfection, and reuse forever!",
"version": "3.1.1.0",
"permissions": [
"identity",
"identity.email",
"clipboardWrite",
"clipboardRead",
"activeTab",
"tabs",
"contextMenus",
"storage",
"webNavigation"
],
"content_security_policy": "script-src 'self' https://ssl.google-analytics.com; object-src 'self'",
"externally_connectable": {
"matches": ["http://*.11trees.com/*"]},
"commands": {
"_execute_browser_action": {
"suggested_key": {
"windows": "Alt+A",
"mac": "Alt+A",
"chromeos": "Alt+A",
"linux": "Alt+A"
}
}
},
"key": "XXX",
"oauth2": {
/*"client_id": "XXX",*/
"client_id": "XXX",
"scopes": [
/*"https://www.googleapis.com/auth/chromewebstore.readonly",*/
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile"
]
},
"background": {
"scripts": ["/dscripts/jquery-3.1.1.min.js","/dscripts/firebase.js","/scripts/background.js"]},
"content_security_policy": "script-src 'self' https://ssl.google-analytics.com https://apis.google.com/ https://www.gstatic.com/ https://*.firebaseio.com https://www.googleapis.com; object-src 'self'",
"content_scripts": [
{
"all_frames" : true,
"matches": ["http://*/*","https://*/*"],
"js": ["/scripts/content.js"]
}
],
"icons": {
"16": "Annotate16.png",
"48": "Annotate48.png",
"128": "Annotate128.png"
},
"browser_action": {
"default_icon": {
"19": "Annotate128.png",
"38": "Annotate128.png"
},
"default_title": "Annotate PRO for Google Chrome",
"default_popup": "aHome.html"
}
}
background.js
//URLs for scripts
var baseURL = "http://localhost/AnnotateX/Scripts/Dev/"; //local server - macOS
var xmlhttp = new XMLHttpRequest(); //why put this up front? We need a new object on each call...
//Firebase constants
var config = {
apiKey: "XXX",
authDomain: "XXX",
databaseURL: "XXX",
storageBucket: "XXX",
// messagingSenderId: "XXX"
};
firebase.initializeApp(config);
//listener for chrome start
chrome.runtime.onStartup.addListener(initApp()); //This fires verification check...
function initApp() {
// Listen for auth state changes.
// [START authstatelistener]
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
var displayName = user.displayName;
var email = user.email;
var emailVerified = user.emailVerified;
// var photoURL = user.photoURL;
// var isAnonymous = user.isAnonymous;
var uid = user.uid;
var providerData = user.providerData;
console.log('We\'re a user...coming through: ' + providerData);
if (user.emailVerified) { //Account is verified
console.log('We\'re a VERIFIED user... ' + emailVerified);
var url1 = baseURL + "aCheckUsers.php"
var url2 = "&fbUserID=" + uid + "&UserEmail=" + email + "&fullName=" + displayName;
$.ajax({
type: "POST",
url: url1,
data: url2,
dataType: 'json',
success: function(arrResult){
arrUserData = arrResult;
console.log('User data: ') + console.log(arrUserData);
localStorage.userDetails = JSON.stringify(arrUserData);
localStorage.userID = arrUserData.userID;
localStorage.licType = arrUserData.LicType;
startup();
},
error: function (jqXHR, textStatus, errorThrown) {
console.log('Error: ' + errorThrown + ' / ' + textStatus) + console.log(jqXHR);
}
});
}
// [START_EXCLUDE]
// [END_EXCLUDE]
} else {
// Let's try to get a Google auth token programmatically.
// [START_EXCLUDE]
console.log('Not a user (background.js)');
// [END_EXCLUDE]
}
});
}
function signOut() {
console.log("Logging out via subroutine in background.js.");
firebase.auth().signOut();
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {method: "logOut"});
});
chrome.browserAction.setPopup({ //Sets popup to last visited
popup: 'aHome.html' // Open this html file within the popup.
});
}
//function that determines whether userID exists and library can be loaded or if new user must be created first
function startup(){
console.log("Starting up...");
chrome.storage.sync.get('lastSave', function(obj) {
var syncSaveTime = obj.lastSave;
var localSaveTime = localStorage.lastSync;
console.log('local: ' + localSaveTime + ' | sync: ' + syncSaveTime);
// if (localSaveTime == null || syncSaveTime >= localSaveTime){ //test
if (localSaveTime == null || syncSaveTime > localSaveTime){ //production
// console.log("Current user: " + localStorage.userID);
console.log("Local version is outdated...should run db pulll...");
pullLibrary();
} //End process for running library load if outdated or NO data locally...
else {
console.log("We've got data - skip the heavyweight pull....use local");
processLibrary(JSON.parse(localStorage.library));
}
}); //End async storage GET
} //End STARTUP
// Firebase auth popups
function googleLoginPopUp() {
var provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider).then(function(result) {
// This gives you a Google Access Token. You can use it to access the Google API.
var token = result.credential.accessToken;
// The signed-in user info.
var user = result.user;
// ...
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// The email of the user's account used.
console.log(errorCode + ' - ' + errorMessage);
// ...
});
} //End Google Login
function facebookLoginPopUp() {
var provider = new firebase.auth.FacebookAuthProvider();
firebase.auth().signInWithPopup(provider).then(function(result) {
// This gives you a Facebook Access Token. You can use it to access the Facebook API.
var token = result.credential.accessToken;
// The signed-in user info.
var user = result.user;
// ...
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log(errorCode + ' - ' + errorMessage);
});
}
Okay...good night's sleep and some basic debugging...
Part of my background.js startup process was to hand the user off to the post-login popup page.
self.location.href='aSearch.html'; //finally open core search page
I don't understand exactly why, but this line in background.js effectively replaced background.js with the aSearch.html and aSearch.js pages...background.js became unavailable to messaging etc.
Removing the line did the trick...and you can't open a page from background.js anyway.

How to retrieve user's additional information from Azure Mobile/App Services?

I need to get the user's extra information from social accounts like Facebook and Google+. When I first read about Azure Mobile Services I thought it to be the holy grail of social authentication. Well, after a full week of hair pulling I'm starting to reconsider my first impression. It does authenticate as easily as it could possibly do. I configured Google+ and FB to work with Azure, configured Azure to use the key/secret from each provider and it all just worked. I was able to login perfectly. The problem started when I tried to get information from the logged user, which I honestly think is basic!
Azure Mobile Services returns the UserId and a Token that you can not use to request the extra info on the selected provider. So even if I were to create a second request using FB's graph API for instance, that wouldn't work (I've tried!). That token is Azure's own token. So I found out from several Carlos Figueira (SE at Azure) posts that I should customize my Azure script, make a request to Azure and then I'd be able to get it working.
I've also read several posts from Carlos Figueira on how to implement that extra functionality and even though that was not what I was looking for (customizing the server) I decided to work with that. But my return type is a MobileServiceUser and that type only has 2 properties: UserId and MobileServiceAuthenticationToken. So even after adding the server script from Carlos I couldn't retrieve the extra information from my Xamarin App.
I've read a lot of things, researched a lot and couldn't find an answer =/ By the way this is not the answer:
How to get user name, email, etc. from MobileServiceUser?
Did anyone manage to make it work?
PS: I'm not posting any code here because it's working. If you think checking some part of my code would help decipher the problem just let me know.
Thanks in advance!
EDIT:
Script
function insert(item, user, request) {
item.UserName = "<unknown>"; // default
user.getIdentities({
success: function (identities) {
var url = null;
var oauth = null;
if (identities.google) {
var googleAccessToken = identities.google.accessToken;
url = 'https://www.googleapis.com/oauth2/v3/userinfo?access_token=' + googleAccessToken;
} else if (identities.facebook) {
var fbAccessToken = identities.facebook.accessToken;
url = 'https://graph.facebook.com/me?access_token=' + fbAccessToken;
} else if (identities.microsoft) {
var liveAccessToken = identities.microsoft.accessToken;
url = 'https://apis.live.net/v5.0/me/?method=GET&access_token=' + liveAccessToken;
} else if (identities.twitter) {
var userId = user.userId;
var twitterId = userId.substring(userId.indexOf(':') + 1);
url = 'https://api.twitter.com/1.1/users/show.json?user_id=' + twitterId;
var consumerKey = process.env.MS_TwitterConsumerKey;
var consumerSecret = process.env.MS_TwitterConsumerSecret;
oauth = {
consumer_key: consumerKey,
consumer_secret: consumerSecret,
token: identities.twitter.accessToken,
token_secret: identities.twitter.accessTokenSecret
};
}
if (url) {
var requestCallback = function (err, resp, body) {
if (err || resp.statusCode !== 200) {
console.error('Error sending data to the provider: ', err);
request.respond(statusCodes.INTERNAL_SERVER_ERROR, body);
} else {
try {
var userData = JSON.parse(body);
item.UserName = userData.name;
request.execute();
} catch (ex) {
console.error('Error parsing response from the provider API: ', ex);
request.respond(statusCodes.INTERNAL_SERVER_ERROR, ex);
}
}
}
var req = require('request');
var reqOptions = {
uri: url,
headers: { Accept: "application/json" }
};
if (oauth) {
reqOptions.oauth = oauth;
}
req(reqOptions, requestCallback);
} else {
// Insert with default user name
request.execute();
}
}
});
}
You're talking about the token on the client side correct? That token is specific only to the client. If you're using Server Side flow, the server is the only one with that token. If you want to send that to the client, you need to do that via a custom API you create.
This class you're talking about does only contain those two properties. But on your server side, your ServiceUser can access the different identity provider tokens in order to speak to those servers APIs. Your linked post is correct in how you access the token, you're mistaken on where you can access that token, it's only on the server side (if you use the server directed login flow).
Here is the custom API Script I had working in Mobile Services to return the profile of the logged in user. I am working on updating to Mobile Apps as some environment variables appear to have changed. Would love to know if anyone has gotten it to work with Mobile Apps.
exports.get = function (request, response) {
var user = request.user;
user.getIdentities({
success: function (identities) {
var req = require('request');
var url = null;
var oauth = null;
var userId = user.userId.split(':')[1];
console.log('Identities: ', identities);
if (identities.facebook) {
url = 'https://graph.facebook.com/me?access_token=' +
identities.facebook.accessToken;
} else if (identities.google) {
url = 'https://www.googleapis.com/oauth2/v3/userinfo' +
'?access_token=' + identities.google.accessToken;
} else if (identities.microsoft) {
url = 'https://apis.live.net/v5.0/me?access_token=' +
identities.microsoft.accessToken;
} else if (identities.twitter) {
var consumerKey = process.env.MS_TwitterConsumerKey;
var consumerSecret = process.env.MS_TwitterConsumerSecret;
oauth = {
consumer_key: consumerKey,
consumer_secret: consumerSecret,
token: identities.twitter.accessToken,
token_secret: identities.twitter.accessTokenSecret
};
url = 'https://api.twitter.com/1.1/users/show.json?' +
'user_id=' + userId + '&include_entities=false';
} else {
response.send(500, { error: 'No known identities' });
return;
}
if (url) {
var reqParams = { uri: url, headers: { Accept: 'application/json' } };
if (oauth) {
reqParams.oauth = oauth;
}
req.get(reqParams, function (err, resp, body) {
if (err) {
console.error('Error calling provider: ', err);
response.send(500, { error: 'Error calling provider' });
return;
}
if (resp.statusCode !== 200) {
console.error('Provider call did not return success: ', resp.statusCode);
response.send(500, { error: 'Provider call did not return success: ' + resp.statusCode });
return;
}
try {
var userData = JSON.parse(body);
response.send(200, userData);
} catch (ex) {
console.error('Error parsing response: ', ex);
response.send(500, { error: ex });
}
});
} else {
response.send(500, { error: 'Not implemented yet', env: process.env });
}
}
});
};

Inserting Google Analytics Content Experiments using the Node.JS Client Library

I'm trying to configure a content experiment using the Node.js Client Library, and have not been able to work out the syntax. Where do I put the body (an Experiment resource) as described here?
https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtExperimentsGuide#insert
This code, for listing existing experiments, works as expected:
var listExperiments = function(){
googleapis
.discover('analytics', 'v3')
.execute(function(err, client) {
var request = client
.analytics.management.experiments.list({
accountId : accountId,
webPropertyId : webPropertyId,
profileId : profileId
})
.withApiKey(browserAPIKey)
.withAuthClient(oauth2Client)
request.execute(function(err,result){
if (err){
console.log(err);
res.send(402);
} else {
console.log(result);
res.send(200);
}
});
});
}
However, when I try to insert a new experiment thusly, I receive a "Field resource is required" error.
var body = {
"name": "myExperimentName",
"status": "READY_TO_RUN",
"objectiveMetric":"ga:bounces",
"variations": [
{ "name": "text1", "url":"http://www.asite.net", "status":"ACTIVE" },
{ "name": "text2", "url":"http://www.asite.net", "status":"ACTIVE" }
]
};
var insertExperiment = function(){
googleapis
.discover('analytics', 'v3')
.execute(function(err, client) {
var request = client
.analytics.management.experiments.insert({
accountId : accountId,
webPropertyId : webPropertyId,
profileId : profileId,
resource : body
})
.withApiKey(browserAPIKey)
.withAuthClient(oauth2Client)
request.execute(function(err,result){
if (err){
console.log(err);
res.send(402);
} else {
console.log(result);
res.send(200);
}
});
});
}
I've tried a few configurations. Management API writes are in limited beta, but I have beta access, so that's not the problem. I've tried inserting the new experiment information directly into the insert() object, calling the experiment info object "body : body " instead of "resource : body", JSON.stringifying the body, and a few other configurations. No luck.
Any help would be great!
I'm aware of this answer, but it uses the Javascript Client Library and makes RESTful requests, whereas I'd like to use the Node Library.
EDIT: Thanks to Burcu Dogan at Google. Here's the correct syntax:
.analytics.management.experiments.insert({
accountId : accountId,
webPropertyId : webPropertyId,
profileId : profileId
}, body)

Oauth for Connect-auth for www.500px.com

I'm trying to extend connect-auth (https://github.com/ciaranj/connect-auth) to connect to http://www.500px.com oauth, but am having issues and can't find a way to debug other than console.log.
I added a strategy five00px.js ( can't name a variable 500px ) as per below, which is a copy of twitter.js strategy with some string substitution.
I keep getting Invalid OAuth Request
Error retrieving the OAuth Request Token: {"statusCode":401,"data":"Invalid OAuth Request"}
I can't really see the OAUTH request as it's in HTTP.
Any idea ?
// five00px.js
/*!
* Copyright(c) 2010 Ciaran Jessup <ciaranj#gmail.com>
* MIT Licensed
*/
var OAuth= require("oauth").OAuth,
url = require("url"),
http = require('http');
module.exports= function(options, server) {
options= options || {}
var that= {};
var my= {};
// Construct the internal OAuth client
my._oAuth= new OAuth("https://api.500px.com/v1/oauth/request_token",
"https://api.500px.com/v1/oauth/access_token",
options.consumerKey, options.consumerSecret,
"1.0A", options.callback || null, "HMAC-SHA1");
console.log('1');
// Give the strategy a name
that.name = "five00px";
// Build the authentication routes required
that.setupRoutes= function(app) {console.log('2setupRoutes');
app.use('/auth/five00px_callback', function(req, res){console.log('3five00px_callback');
req.authenticate([that.name], function(error, authenticated) {console.log('4authenticate');
res.writeHead(303, { 'Location': req.session.five00px_redirect_url });
res.end('');
});
});
}
// Declare the method that actually does the authentication
that.authenticate= function(request, response, callback) {console.log('5authenticate');
//todo: if multiple connect middlewares were doing this, it would be more efficient to do it in the stack??
var parsedUrl= url.parse(request.originalUrl, true);
this.trace('parsedUrl=' + request.originalUrl);
//todo: makw the call timeout ....
var self= this;
if( request.getAuthDetails()['500px_login_attempt_failed'] === true ) {
// Because we bounce through authentication calls across multiple requests
// we use this to keep track of the fact we *Really* have failed to authenticate
// so that we don't keep re-trying to authenticate forever.
delete request.getAuthDetails()['500px_login_attempt_failed'];
self.fail( callback );
}
else {
if( parsedUrl.query && parsedUrl.query.denied ) {
self.trace( 'User denied OAuth Access' );
request.getAuthDetails()['500px_login_attempt_failed'] = true;
this.fail(callback);
}
else if( parsedUrl.query && parsedUrl.query.oauth_token && request.session.auth["500px_oauth_token_secret"] ) {
self.trace( 'Phase 2/2 : Requesting an OAuth access token.' );
my._oAuth.getOAuthAccessToken(parsedUrl.query.oauth_token, request.session.auth["500px_oauth_token_secret"],
function( error, oauth_token, oauth_token_secret, additionalParameters ) {
if( error ) {
self.trace( 'Error retrieving the OAuth Access Token: ' + error );
request.getAuthDetails()['500px_login_attempt_failed'] = true;
this.fail(callback);
}
else {
self.trace( 'Successfully retrieved the OAuth Access Token' );
request.session.auth["500px_oauth_token_secret"]= oauth_token_secret;
request.session.auth["500px_oauth_token"]= oauth_token;
var user= { user_id: additionalParameters.user_id,
username: additionalParameters.screen_name }
self.executionResult.user= user;
self.success(user, callback)
}
});
}
else {
my._oAuth.getOAuthRequestToken(function(error, oauth_token, oauth_token_secret, oauth_authorize_url, additionalParameters ) {
if(error) {
self.trace( 'Error retrieving the OAuth Request Token: ' + JSON.stringify(error) );
callback(null); // Ignore the error upstream, treat as validation failure.
} else {
self.trace( 'Successfully retrieved the OAuth Request Token' );
request.session['500px_redirect_url']= request.originalUrl;
request.session.auth["500px_oauth_token_secret"]= oauth_token_secret;
request.session.auth["500px_oauth_token"]= oauth_token;
self.redirect(response, "https://api.500px.com/oauth/authenticate?oauth_token=" + oauth_token, callback);
}
});
}
}
}
return that;
};
Have to use OAuth 1.0 (instead of 1.0A)
my._oAuth= new OAuth("https://api.500px.com/v1/oauth/request_token",
"https://api.500px.com/v1/oauth/access_token",
options.consumerKey, options.consumerSecret,
"1.0",
options.callback || null, "HMAC-SHA1");

Resources