Outputting Google API Calls Inside Chrome Extension - javascript

My aim is to output some of my Google Analytics data inside a new-tab page using a Chrome extension.
I've followed the "Hello Analytics API: JavaScript quickstart for web applications" found at
https://developers.google.com/analytics/devguides/reporting/core/v3/quickstart/web-js#clientId as the basis for my new-tab page:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello Analytics - A quickstart guide for JavaScript</title>
</head>
<body>
<button id="auth-button" hidden>Authorize</button>
<h1>Hello Analytics</h1>
<textarea cols="80" rows="20" id="query-output"></textarea>
<script>
// Replace with your client ID from the developer console.
var CLIENT_ID = 'TAKEN OUT FOR SECURITY';
// Set authorized scope.
var SCOPES = ['https://www.googleapis.com/auth/analytics.readonly'];
function authorize(event) {
// Handles the authorization flow.
// `immediate` should be false when invoked from the button click.
var useImmdiate = event ? false : true;
var authData = {
client_id: CLIENT_ID,
scope: SCOPES,
immediate: useImmdiate
};
gapi.auth.authorize(authData, function(response) {
var authButton = document.getElementById('auth-button');
if (response.error) {
authButton.hidden = false;
}
else {
authButton.hidden = true;
queryAccounts();
}
});
}
function queryAccounts() {
// Load the Google Analytics client library.
gapi.client.load('analytics', 'v3').then(function() {
// Get a list of all Google Analytics accounts for this user
gapi.client.analytics.management.accounts.list().then(handleAccounts);
});
}
function handleAccounts(response) {
// Handles the response from the accounts list method.
if (response.result.items && response.result.items.length) {
// Get the first Google Analytics account.
var firstAccountId = response.result.items[0].id;
// Query for properties.
queryProperties(firstAccountId);
} else {
console.log('No accounts found for this user.');
}
}
function queryProperties(accountId) {
// Get a list of all the properties for the account.
gapi.client.analytics.management.webproperties.list(
{'accountId': accountId})
.then(handleProperties)
.then(null, function(err) {
// Log any errors.
console.log(err);
});
}
function handleProperties(response) {
// Handles the response from the webproperties list method.
if (response.result.items && response.result.items.length) {
// Get the first Google Analytics account
var firstAccountId = response.result.items[0].accountId;
// Get the first property ID
var firstPropertyId = response.result.items[0].id;
// Query for Views (Profiles).
queryProfiles(firstAccountId, firstPropertyId);
} else {
console.log('No properties found for this user.');
}
}
function queryProfiles(accountId, propertyId) {
// Get a list of all Views (Profiles) for the first property
// of the first Account.
gapi.client.analytics.management.profiles.list({
'accountId': accountId,
'webPropertyId': propertyId
})
.then(handleProfiles)
.then(null, function(err) {
// Log any errors.
console.log(err);
});
}
function handleProfiles(response) {
// Handles the response from the profiles list method.
if (response.result.items && response.result.items.length) {
// Get the first View (Profile) ID.
var firstProfileId = response.result.items[0].id;
// Query the Core Reporting API.
queryCoreReportingApi(firstProfileId);
} else {
console.log('No views (profiles) found for this user.');
}
}
function queryCoreReportingApi(profileId) {
// Query the Core Reporting API for the number sessions for
// the past seven days.
gapi.client.analytics.data.ga.get({
'ids': 'ga:' + profileId,
'start-date': '7daysAgo',
'end-date': 'today',
'metrics': 'ga:sessions'
})
.then(function(response) {
var formattedJson = JSON.stringify(response.result, null, 2);
document.getElementById('query-output').value = formattedJson;
})
.then(null, function(err) {
// Log any errors.
console.log(err);
});
}
// Add an event listener to the 'auth-button'.
document.getElementById('auth-button').addEventListener('click', authorize);
</script>
<script src="https://apis.google.com/js/client.js?onload=authorize"></script>
</body>
</html>
I get the following errors:
Refused to execute inline script because it violates the following
Content Security Policy directive: "script-src 'self' blob:
filesystem: chrome-extension-resource:". Either the 'unsafe-inline'
keyword, a hash
('sha256-ZJ1hGXIQLHmnXhFZqYWEDfv/ypJQ/Yvh6mYGne3Nf0s='), or a nonce
('nonce-...') is required to enable inline execution.
Refused to load the script 'https://apis.google.com/js/client.js?onload=authorize' because it violates the following Content Security Policy directive: "script-src 'self' blob: filesystem: chrome-extension-resource:".
Please advise.
Thanks,
Jack

By default, inline script(Your first error) won't be executed, and only local script is loaded (Your second error).
To solve this, take a look at Content Security Policy, the recommendation would be extracting inline script to an external script (Your first error) and making a local copy of remote script (Your second error).

Related

Google Sheets Javascript won't load in browser

<!DOCTYPE html>
<html>
<head>
<title>Google Sheets API Quickstart</title>
<meta charset='utf-8' />
</head>
<body>
<p>Google Sheets API Quickstart</p>
<!--Add buttons to initiate auth sequence and sign out-->
<button id="authorize-button" style="display: none;">Authorize</button>
<button id="signout-button" style="display: none;">Sign Out</button>
<pre id="content"></pre>
<script type="text/javascript">
// Client ID and API key from the Developer Console
var CLIENT_ID = '<YOUR_CLIENT_ID>';
// Array of API discovery doc URLs for APIs used by the quickstart
var DISCOVERY_DOCS = ["https://sheets.googleapis.com/$discovery/rest?version=v4"];
// Authorization scopes required by the API; multiple scopes can be
// included, separated by spaces.
var SCOPES = "https://www.googleapis.com/auth/spreadsheets.readonly";
var authorizeButton = document.getElementById('authorize-button');
var signoutButton = document.getElementById('signout-button');
/**
* On load, called to load the auth2 library and API client library.
*/
function handleClientLoad() {
gapi.load('client:auth2', initClient);
}
/**
* Initializes the API client library and sets up sign-in state
* listeners.
*/
function initClient() {
gapi.client.init({
discoveryDocs: DISCOVERY_DOCS,
clientId: CLIENT_ID,
scope: SCOPES
}).then(function () {
// Listen for sign-in state changes.
gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
// Handle the initial sign-in state.
updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
authorizeButton.onclick = handleAuthClick;
signoutButton.onclick = handleSignoutClick;
});
}
/**
* Called when the signed in status changes, to update the UI
* appropriately. After a sign-in, the API is called.
*/
function updateSigninStatus(isSignedIn) {
if (isSignedIn) {
authorizeButton.style.display = 'none';
signoutButton.style.display = 'block';
listMajors();
} else {
authorizeButton.style.display = 'block';
signoutButton.style.display = 'none';
}
}
/**
* Sign in the user upon button click.
*/
function handleAuthClick(event) {
gapi.auth2.getAuthInstance().signIn();
}
/**
* Sign out the user upon button click.
*/
function handleSignoutClick(event) {
gapi.auth2.getAuthInstance().signOut();
}
/**
* Append a pre element to the body containing the given message
* as its text node. Used to display the results of the API call.
*
* #param {string} message Text to be placed in pre element.
*/
function appendPre(message) {
var pre = document.getElementById('content');
var textContent = document.createTextNode(message + '\n');
pre.appendChild(textContent);
}
/**
* Print the names and majors of students in a sample spreadsheet:
* https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
*/
function listMajors() {
gapi.client.sheets.spreadsheets.values.get({
spreadsheetId: '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms',
range: 'Class Data!A2:E',
}).then(function(response) {
var range = response.result;
if (range.values.length > 0) {
appendPre('Name, Major:');
for (i = 0; i < range.values.length; i++) {
var row = range.values[i];
// Print columns A and E, which correspond to indices 0 and 4.
appendPre(row[0] + ', ' + row[4]);
}
} else {
appendPre('No data found.');
}
}, function(response) {
appendPre('Error: ' + response.result.error.message);
});
}
</script>
<script async defer src="https://apis.google.com/js/api.js"
onload="this.onload=function(){};handleClientLoad()"
onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
</body>
</html>
Admittedly, I'm relatively new at much of this.
But I'm trying to create a simple landing page that is connected to a Google Sheet. I want to host it as a subdomain off of my main website. However, I can't seem to get it to actually load the information. It works fine when I run it locally, but something seems to be stopping it in the browser.
I've also tried to get their own example code to run off of my website, but it has the same problem and error message.
The error I keep getting appears to be the following:
"Not a valid origin for the client."
error: "idpiframe_initialization_failed"
To see what it is doing, check out http://thomasconant.com/teamStats2.html
Does anyone recognize this error and can suggest what I can do to fix it?
You forgot to replace YOUR_CLIENT_ID with the actual client id you got.
What does your page which generates this error look like? It's hard to say without the code.
If you're using the Google API Client in Javascript, and this is a console error, I'm thinking that you have not added the correct origin to your Google Developer Console.
Error: origin_mismatch
This error will occur during the authorization flow if the host and port used to serve the web page doesn't match an allowed JavaScript origin on your Google Developers Console project. Make sure you completed the Step 1.e and that the URL in your browser matches.
(If this is the correct answer, don't forget to mark it!) :)

Google Sign In not being signed in when page refreshes (Polymer)

I'm implementing "Google Sign In" into my website to handle all user authentication etc.. I will have a back-end database that I use to store information against users to keep track of their profile and their actions etc..
I've followed the Google Developer documentation and have got a "Google Sign In" button on a web page and when this button is clicked I choose my account and am signed in and the id_token goes off and is authenticated with my back-end server successfully. The only problem I'm now having is that when I refresh the page the button is back to "Sign In" rather than staying signed in, is this normal behaviour or is there something I'm missing? I don't want users to have to have to sign in again whenever the page changes.
On a side note I have managed to store the id_token from successfully logging into Google in localStorage and then using this id_token to re-authenticate with the back-end server automatically (as you can see in the commented out code) but this doesn't obviously automatically change the status of the "Google Sign In" button which would confuse users on the client-side.
Can anyone shed any light on this problem please?
Not signed in:
After signing in (doesn't currently stay like this after a page refresh):
login.html:
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./css/base.css"/> <!-- Base CSS -->
<script src="./js/all.js"></script> <!-- All JavaScript file -->
<script src="./js/Logger.class.js"></script> <!-- Logger class -->
<script src="./bower_components/jquery/dist/jquery.min.js"></script> <!-- jQuery -->
<script src="./js/gSignIn.js"></script>
<!-- Polymer -->
<script src="./bower_components/webcomponentsjs/webcomponents-lite.min.js"></script> <!-- Web Components Import -->
<!-- Element Imports -->
<link rel="import" href="./bower_components/paper-button/paper-button.html"/>
<link rel="import" href="./bower_components/google-signin/google-signin.html"/>
</head>
<body>
<google-signin id="gSignIn" client-id="--- REMOVED FOR PRIVACY ---" scopes="profile email openid"></google-signin>
Sign Out
</body>
</html>
gSignIn.js:
/**
* Google Sign In JavaScript
*/
$(document).ready(function() {
var logger = new Logger("gSignIn.js", false); // logger object
var id_token = null;
logger.log("Load", "Successful");
// Try to automatically login
// if (localStorage !== null) { // If local storage is available
// if (localStorage.getItem("gIDToken") !== null) { // If the Google ID token is available
// id_token = localStorage.getItem("gIDToken");
// // Send off AJAX request to verify on the server
// $.ajax({
// type: "POST",
// url: window.api.url + "googleauth/verify/",
// data: { "id_token": id_token },
// success: function (data) {
// if (!data.error) { // If there was no error
// logger.log("Google SignIn", "Successfully signed in!");
// }
// }
// });
// }
// }
/**
* EVENT: Google SignIn success
*/
$("#gSignIn").on("google-signin-success", function () {
id_token = getGoogleAuthResponse().id_token;
var profile = getGoogleProfile();
console.log("ID: " + profile.getId()); // Don't send this directly to your server!
console.log("Name: " + profile.getName());
console.log("Image URL: " + profile.getImageUrl());
console.log("Email: " + profile.getEmail());
// Send off AJAX request to verify on the server
$.ajax({
type: "POST",
url: window.api.url + "googleauth/verify/",
data: { "id_token": id_token },
success: function (data) {
if (!data.error) { // If there was no error
logger.log("Google SignIn", "Successfully signed in!");
// Store the id_token
if (localStorage !== null) { // If localStorage is available
localStorage.setItem("gIDToken", id_token); // Store the id_token
}
}
}
});
});
$("#signOut").click(function () {
var auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(function () {
console.log("User signed out.");
});
});
/**
* Get Google Profile
*
* #returns object
*/
var getGoogleProfile = function () {
var profile = gapi.auth2.getAuthInstance().currentUser.get().getBasicProfile();
return profile;
};
/**
* Get Google Auth Response
*
* #returns object
*/
var getGoogleAuthResponse = function () {
var response = gapi.auth2.getAuthInstance().currentUser.get().getAuthResponse();
return response;
};
});
Thanks!
I had the same problem and, after ensuring third party cookies were enabled, it came down to the hostname, localhost in this case.
In the end, I had to fake a domain using /etc/hosts, ensure google developers dashboard has that domain whitelisted, and start using that domain instead of localhost.
I can only assume that gapis don't like localhost, even though it's whitelisted in my google developers dashboard for the account I'm using. If you do manage to get localhost to work, do give me a shout!
Another way to do this is to access localhost from a nonstandard port (not 80). I managed to get around this headache by using an nginx proxy from port 80 to 81:
server {
listen 81;
location / {
proxy_pass http://localhost:80;
}
}

Polymer HTML5 Web Component for Google Drive Picker API - target origin error

So I am trying to start a API call to the Google Picker API, and I can connect my account, but after that it says my API key is invalid.
The API and client numbers are the exact ones found within my Google developer console and the API was created for a web browser app.
This is in the console:
Failed to execute 'postMessage' on 'DOMWindow': The target origin
provided ('https://docs.google.com') does not match the recipient
window's origin ('http://w1nz.co').
Uncaught ReferenceError: init is not defined
I have tracked this error to happen when the PickerBuilder is at the .build() line.
You can view this live at http://w1nz.co/polymer-app/
This is a Polymer HTML5 Web Component so whatever is within the <template> tags is rendered to the page.
My Code:
<link rel="import" href="/polymer-app/bower_components/polymer/polymer.html">
<polymer-element name="drive-save" noscript>
<template>
<script src="https://apis.google.com/js/platform.js"></script>
<script>
var clientId = '185720521988-0vifnru5llc3mqj1k7evil99vnghagid.apps.googleusercontent.com';
var developerKey = 'AIzaSyDDTPAGVNFWG2czBBx8QFjn4Vg3KZoEccE';
var oauthToken;
function onApiLoad() {
gapi.load('auth', authenticateWithGoogle);
gapi.load('picker');
}
function authenticateWithGoogle() {
window.gapi.auth.authorize({
'client_id': clientId,
'scope': ['https://www.googleapis.com/auth/drive']
}, handleAuthentication);
}
function handleAuthentication(result) {
console.log(result);
if(result && !result.error) {
oauthToken = result.access_token;
setupPicker();
}
}
function setupPicker() {
var picker = new google.picker.PickerBuilder().
.addView(new google.picker.DocsUploadView())
setOAuthToken(oauthToken).
setDeveloperKey(developerKey).
setCallback(pickerCallback).
build();
picker.setVisible(true);
}
function pickerCallback(data) {
console.log(data);
if (data.action == google.picker.Action.PICKED) {
alert(data.docs[0].name);
} else if (data.action == google.picker.Action.CANCEL) {
alert('goodbye');
}
}
</script>
<script src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
<p>Hello World</p>
</template>
</polymer-element>
I tried by just commenting the below line ..
setDeveloperKey(developerKey) //No need to set dev key
and it works perfectly fine..Please try!!!
I don't tried yet for myself, but you you would not be trying to reach a unencrypted target from a encrypted connection (ssl) origin?

How do I get email address field using the LinkedIn Javascript API?

I'm using the LinkedIn Javascript API to sign in users to my application, however the API is not returning the email address even though I'm requiring permission for that specific field. I'm including the API script as follows:
<script type="text/javascript" src="//platform.linkedin.com/in.js">
api_key: API_KEY
scope: r_fullprofile r_emailaddress
</script>
then I'm including the Log In button in the markup:
<script type="in/Login" data-onAuth="onLinkedInAuth">
and finally I have a function to add the callback for the API response:
function onLinkedInAuth() {
var fields = ['first-name', 'last-name', 'email-address'];
IN.API.Profile("me").fields(fields).result(function(data) {
console.log(data);
}).error(function(data) {
console.log(data);
});
};
I'm only getting the First and Last Name but the API doesn't return the email field.
Reference: https://developer.linkedin.com/documents/profile-fields#email
1- be sure you made email permission (r_emailaddress) in your app http://developer.linkedin.com/documents/authentication#granting
2- then you may use this
<script type="text/javascript" src="http://platform.linkedin.com/in.js">
api_key: key
**onLoad: onLinkedInLoad**
authorize: true
</script>
<script>
function onLinkedInLoad() {
IN.Event.on(IN, "auth", onLinkedInAuth);
}
// 2. Runs when the viewer has authenticated
function onLinkedInAuth() {
IN.API.Profile("me").fields("first-name", "last-name", "email-address").result(function (data) {
console.log(data);
}).error(function (data) {
console.log(data);
});
}
</script>
hope this will help you :)
thanks
Hello there #Ulises Figueroa,
May be I am coming in a bit late but this is how I had got this done:
Start off with the initial script tag on the top of your page within the head section:
<script>
Client Id Number here:
onLoad: onLinkedInLoad
authorize: true
</script>
Then, in your JS File,(I had placed an external JS File to process this API sign up/ Auth), have the following details placed:
function onLinkedInLoad() {
IN.Event.on(IN, "auth", getProfileData);
}
function onSuccess(data) {
console.log(data);
}
function onError(error) {
console.log(error);
}
function getProfileData(){
IN.API.Profile("me").fields(["firstName","lastName", "email-address", "positions"]).result(function(data) {
var profileData = data.values[0];
var profileFName = profileData.firstName;
var profileLName = profileData.lastName;
if(data.values[0].positions._total == "0" || data.values[0].positions._total == 0 || data.values[0].positions._total == undefined) {
console.log("Error on position details");
var profileCName = "Details Are Undefined";
}
else {
var profileCName = profileData.positions.values["0"].company.name;
}
var profileEName = profileData.emailAddress;
//console.log all the variables which have the data that
//has been captured through the sign up auth process and
//you should get them...
});
}
Then last but not the least, add the following in your HTML DOCUMENT which can help you initiate the window popup for the linkedin auth sign up form:
<script type="in/Login"></script>
The above setup had worked for me. Sure this will help you out.
Cheers and have a nice day.
Implementation looks good. I'd believe this is a result from the profile's privacy settings. Per linked-in's docs:
Not all fields are available for all profiles. The fields available depend on the relationship between the user you are making a request on behalf of and the member, the information that member has chosen to provide, and their privacy settings. You should not assume that anything other than id is returned for a given member.
I figured out that this only happens with certain LinkedIn accounts, so this might be caused because some privacy setting with the email. I couldn't find any reference to the documentation so I had to consider the case when email field is not available.

Unsafe JavaScript attempt to access frame with URL when using Twitter/Facebook

I am building a website using the Twitter and Facebook JavaScript SDKs. I am attempting to perform tweets and facebook shares from the site. But I am getting the following error when I try to send a tweet OR facebook share from my website:
Chrome:
Unsafe JavaScript attempt to access frame with URL http://edro.no-ip.org:3000/#_=_ from frame with URL http://platform.twitter.com/widgets/tweet_button.1354761327.html#_=1355186876357&count=none&id=twitter-widget-0&lang=en&original_referer=http%3A%2F%2Fedro.no-ip.org%3A3000%2F%23_%3D_&related=xbox%3AGhostfire%20Games&size=m&text=Check%20out%20this%20fun%20story!%20%23atalltale&url=http%3A%2F%2Fedro.no-ip.org%3A3000%2Fstories%2FiqU9xW1FJI. The frame requesting access set 'document.domain' to 'twitter.com', but the frame being accessed did not. Both must set 'document.domain' to the same value to allow access.
Safari:
Unsafe JavaScript attempt to access frame with URL http://edro.no-ip.org:3000/ from frame with URL http://platform.twitter.com/widgets/tweet_button.1354761327.html#_=1355197702032&count=none&id=twitter-widget-0&lang=en&original_referer=http%3A%2F%2Fedro.no-ip.org%3A3000%2F&related=xbox%3AGhostfire%20Games&size=m&text=Check%20out%20this%20fun%20story!%20%23atalltale&url=http%3A%2F%2Fedro.no-ip.org%3A3000%2Fstories%2FiqU9xW1FJI. Domains, protocols and ports must match.
Here's the code (I only included the relevant parts):
<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="https://www.facebook.com/2008/fbml">
<head>
<title>Title</title>
<link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
</body>
<center>
<h1>Page Header</h1>
&nbsp
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
<div id="fb-root"></div>
<script type="text/javascript">
// Once the Facebook SDK is fully loaded, this callback will be invoked
window.fbAsyncInit = function()
{
FB.init({
appId: "250634021702621",
status: true,
cookie: true,
channelUrl: '//edro.no-ip.org:3000/channel.html',
});
FB.Event.subscribe('auth.statusChange', handleStatusChange);
};
// Callback for once we are logged in and authorized
function handleStatusChange(response) {
document.body.className = response.authResponse ? 'connected' : 'not_connected';
if (response.authResponse)
{
}
};
// Declare a generic SDK loading function
var loadSDK = function(doc, script, id, src)
{
var js, fjs = doc.getElementsByTagName(script)[0];
if (!doc.getElementById(id))
{
js = doc.createElement(script);
js.id = id;
js.src = src;
js.async = true; // Makes SDK load asynchronously
fjs.parentNode.insertBefore(js,fjs);
}
};
// Twitter SDK loading
loadSDK(document, 'script', 'twitter-wjs', 'https://platform.twitter.com/widgets.js');
// Facebook SDK loading
loadSDK(document, 'script', 'facebook-jssdk', '//connect.facebook.net/en_US/all.js');
// Facebook callback - useful for doing stuff after Facebook returns. Passed as parameter to API calls later.
var myResponse;
function callback(response)
{
if (response)
{
// For debugging - can query myResponse via JavaScript console
myResponse = response;
if (response.post_id)
{
}
else
{
// Else we are expecting a Response Body Object in JSON, so decode this
var responseBody = JSON.parse(response.body);
// If the Response Body includes an Error Object, handle the Error
if(responseBody.error)
{
}
// Else handle the data Object
else
{
}
}
}
}
// All API calls go here
$(document).ready(function ()
{
// Post to your wall
$('#post_wall').click(function ()
{
FB.ui(
{
method: 'feed',
// useful if we want the callback to go to our site, rather than the JavaScript, so we can log an event
redirect_uri: 'http://edro.no-ip.org:3000',
link: 'http://edro.no-ip.org:3000/stories/{game.id}',
picture: 'http://fbrell.com/f8.jpg',
name: 'name',
caption: 'caption',
description: 'description'
// display: 'popup'
},
callback
);
return false;
});
});</script>
<!-- Tweet code-->
Tweet
<!-- Facebook share code-->
<p id="msg">Share on Facebook</p>
</center>
</html>
"Domains, protocols and ports must match."
Typical mismatch in (older versions of ?) Safari is http://www.example.com and http://example.com.

Categories