Commit fdfdc940 authored by Elia Bravo's avatar Elia Bravo
Browse files

First Commit

parents
Play_Green.png

863 Bytes

Firebase Auth w/ Google Sign-In in Chrome Extensions
====================================================
This sample demonstrates how to authorize a user with Firebase in a Chrome extension using Google Sign-In and setup the Chrome extension to allow the use of the Realtime Database and Firebase Storage.
Introduction
------------
- [Read more about Firebase Auth](https://firebase.google.com/docs/auth/)
Setting up this sample
---------------
### Creating a dummy Chrome extension (how to obtain a Chrome App ID and Public Key)
Setting up authentication in Chrome extensions is a bit of a chicken vs. egg problem. You need the **Public Key** and **Chrome App ID** to configure your manifest.json file, but you have to publish that to the Chrome Store to get the values. So we will publish a dummy app in order to obtain these.
Create a new directory and add a `manifest.json` file similar to the following:
{
"manifest_version": 2,
"name": "Firebase Auth in Chrome Extension Sample",
"description": "This sample shows how to authorize Firebase in a Chrome extension using a Google account.",
"version": "0.1",
"permissions": [
"identity"
]
}
Zip the directory:
cd ..
zip -r <chrome ext name>.zip <directory name>
Upload the dummy extension to the app store by going to the [Chrome App Developer Dashboard](https://chrome.google.com/webstore/developer/dashboard) and clicking **Add a New Item**. For more reading on publishing to the Chrome Web Store, go [here](https://developer.chrome.com/webstore/publish).
> Of course if you already own an extension and would like to add Firebase to it, skip the steps above.
Once the extension is uploaded and visible under **Your Listings**, click the **more info** link to the right. Copy down both the **Item ID** (e.g. `kjdohecpbfnjbinmakjcmpgpbbhhijgf`) and **Public Key** (e.g. `MIIBIjANBgkqhkiG9w0B...long string of text...unbQIDAQAB`). You will need both of these below.
### Creating an OAuth Client
- Create a new **OAuth Client ID** in [your project's Developers Console](https://console.developers.google.com/apis/credentials/oauthclient?project=_) (Click this link and select your Firebase project).
- Select **Chrome App** and enter your Chrome Extension/App ID (the `Item ID` obtained above).
- Note the `Client ID` (e.g. `7159....j00.apps.googleusercontent.com`) as you will need this below.
### Configuring your Firebase Project
- Create or select a Firebase project at [Firebase Console](https://console.firebase.google.com).
- Enable the **Google** authentication method in the **Auth** section > **SIGN IN METHOD** tab.
- Add the Client ID you created to the whitelist using the **Whitelist client IDs from external projects (optional)**
- Edit the `credential.js` and `background.js` and enter your project's identifiers you get from the Firebase Console **Overview > Add Firebase to your web app**.
- Edit the `manifest.json`
- Enter your **OAuth Client ID** and your extension's **Public Key**.
- Remove all comment lines (starting with `//`) in the `manifest.json` file before deploying your extension online.
- Install the Extension in your browser and click on the extension's icon once installed. The first time your users will install the extension they will have to authorize Firebase using the login button.
Using Firebase in your own extension
------------------------------------
The keys to using Firebase in a Chrome extension are:
- Because of Chrome Extensions' [Content Security Policy](https://developer.chrome.com/extensions/contentSecurityPolicy) you need to avoid inline JavaScript in your HTML pages so you need to add the Firebase initialisation snippet in your JS file instead of inside the HTML file as we [typically instruct](https://firebase.google.com/docs/web/setup). The Firebase initialisation snippet looks like this:
```javascript
// Initialize Firebase
var config = {
apiKey: "<qwertyuiopasdfghjklzxcvbnm>",
databaseURL: "https://<my-app-id>.firebaseio.com",
storageBucket: "<my-app-id>.appspot.com"
};
firebase.initializeApp(config);
```
- Create a Google Client ID that's authorized for your Chrome extension and whitelist it in your Firebase project:
- Create a new OAuth Client ID in your project's [Developers Console](https://console.developers.google.com/apis/credentials/oauthclient?project=_), Select **Chrome App** and enter your Chrome Extension/App ID.
- In your project's Firebase Console, enable the **Google** authentication method in the **Auth** section > **SIGN IN METHOD** tab.
- Add the Client ID you created to the whitelist using the **Whitelist client IDs from external projects (optional)**
- Use the chrome.identity API to get a Google OAuth token as described in https://developer.chrome.com/apps/app_identity and then use this token to authorize Firebase using [Auth.signInWithCredential()](https://firebase.google.com/docs/reference/js/firebase.auth.Auth#signInWithCredential):
```javascript
var credential = firebase.auth.GoogleAuthProvider.credential(null, token);
firebase.auth().signInWithCredential(credential);
```
- Add the following content security policy to your `manifest.json` to allow importing the Firebase SDK and accessing the Realtime Database as well as Firebase Storage:
```javascript
"content_security_policy":"script-src 'self' https://www.gstatic.com/ https://*.firebaseio.com https://www.googleapis.com; object-src 'self'"
```
Support
-------
https://firebase.google.com/support/
License
-------
© Google, 2016. Licensed under an [Apache-2](../../LICENSE) license.
<!DOCTYPE html>
<!--
Copyright (c) 2016 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<meta charset=utf-8 />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Digital Wellbeing Exercise</title>
<link rel="stylesheet" href="main.css">
<!-- ***************************************************************************************
* TODO(DEVELOPER): Make sure you are importing the latest version of the Firebase JS. *
*************************************************************************************** -->
<script src="https://www.gstatic.com/firebasejs/7.5.0/firebase.js"></script>
<script src="background.js"></script>
</head>
<body>
</body>
</html>
This diff is collapsed.
// TODO(DEVELOPER): Change the values below using values from the initialization snippet: Firebase Console > Overview > Add Firebase to your web app.
// Initialize Firebase
src="https://www.gstatic.com/firebasejs/7.10.0/firebase-app.js"
src="https://www.gstatic.com/firebasejs/7.10.0/firebase-analytics.js"
var config = {
apiKey: "AIzaSyCCPYKyRSSOZBIPR6Pp7m8EA6yg0rDb0fo",
authDomain: "socialize-d38e1.firebaseapp.com",
databaseURL: "https://socialize-d38e1.firebaseio.com",
projectId: "socialize-d38e1",
storageBucket: "socialize-d38e1.appspot.com",
messagingSenderId: "531289543247",
appId: "1:531289543247:web:ccac57c58c4e26d6bbd03a",
measurementId: "G-XYBLDXNCP5"
};
var lastUrl = null
var interval = 0
var prevWindowId = -1
var uid
//if (!firebase.apps.length){
app = firebase.initializeApp(config);
db = firebase.firestore(app);
//}
initApp();
//timers = new Map()
//getAllTimers(timers)
/**
* initApp handles setting up the Firebase context and registering
* callbacks for the auth status.
*
* The core initialization is in firebase.App - this is the glue class
* which stores configuration. We provide an app name here to allow
* distinguishing multiple app instances.
*
* This method also registers a listener with firebase.auth().onAuthStateChanged.
* This listener is called when the user is signed in or out, and that
* is where we update the UI.
*
* When signed in, we also authenticate to the Firebase Realtime Database.
*/
function initApp() {
// Listen for auth state changes.
firebase.auth().onAuthStateChanged(function(user) {
console.log('User state change detected from the Background script of the Chrome Extension:', user);
if (user){
uid = user.uid;
}
});
}
chrome.tabs.onRemoved.addListener(function (tabId, removeInfo){
clearInterval(interval)
});
/*
chrome.tabs.onUpdated.addListener(function(id, info, tab) {
clearInterval(interval);
//var tabId = info.tabId;
//var windowId = info.windowId;
//alert("info.tabId: "+ info.tabId);
//chrome.tabs.getSelected(null, function(tab) {
var url = new URL(tab.url)
if (lastUrl != tab.url){
//alert("LAST URL: "+lastUrl+ " URL: "+tab.url)
//alert("Updated!")
lastUrl = tab.url;
//alert("Current URL: "+ url);
var domain = url.hostname
//alert("Domain: "+ domain);
//get timer for tab.url, set timeout
var timer = null
var docRef2 = db.collection("users").doc(uid)
alert (docRef2);
var docRef = docRef2.collection("timers").doc(domain);
docRef.get().then(function(doc) {
if (doc.exists) {
timer = doc.data()
//alert("doc.id "+doc.id)
if (timer != null){
var seconds = timer.Timestamp.seconds
//myVar = setTimeout(function(){ alert("Timeout set for URL "+ domain); }, seconds);
//alert("timer: "+ seconds);
var interval = setInterval(function(){
if (seconds == 1){
//alert ("Timeout expired for domain: "+ domain)
//chrome.tabs.create({url:"blockingPopUp.html"});
window.open("blockingPopUp.html");
chrome.tabs.remove(tab.id, function() { });
clearInterval(interval);
}
else {
seconds = seconds -1
//alert("Remaining seconds: "+ seconds)
var timestamp = firebase.firestore.Timestamp.fromMillis(seconds*1000)
//alert("doc.id "+doc.id)
chrome.tabs.getSelected(null, function(tab) {
var url = new URL(tab.url)
//alert("Current URL: "+ url);
var domain = url.hostname
chrome.windows.get(tab.windowId, function(chromeWindow) {
if (chromeWindow.state === "minimized") {
// Window is minimized
clearInterval(interval)
} else {
// Window is not minimized (maximized, fullscreen or normal)
if (domain == doc.id){
docRef.set({
Timestamp: timestamp,
});
} else clearInterval(interval)
}
});
});
}
}, 1000);
}
}
}).catch(function(error) {
console.log("Error getting document:", error);
});
//});
}
});
*/
chrome.windows.onFocusChanged.addListener(function(windowId) {
if (windowId == chrome.windows.WINDOW_ID_NONE) {
clearInterval(interval)
}
});
/*
chrome.tabs.onActivated.addListener(function(activeInfo) {
clearInterval(interval);
//var tabId = info.tabId;
//var windowId = info.windowId;
//alert("info.tabId: "+ info.tabId);
chrome.tabs.getSelected(null, function(tab) {
var url = new URL(tab.url)
if (lastUrl != tab.url){
//alert("LAST URL: "+lastUrl+ " URL: "+tab.url)
//alert("Updated!")
lastUrl = tab.url;
//alert("Current URL: "+ url);
var domain = url.hostname
//alert("Domain: "+ domain);
//get timer for tab.url, set timeout
var timer = null
var docRef = db.collection("users").doc(uid).collection("timers").doc(domain);
docRef.get().then(function(doc) {
if (doc.exists) {
timer = doc.data()
//alert("doc.id "+doc.id)
if (timer != null){
var seconds = timer.Timestamp.seconds
//myVar = setTimeout(function(){ alert("Timeout set for URL "+ domain); }, seconds);
//alert("timer: "+ seconds);
var interval = setInterval(function(){
if (seconds == 1){
//alert ("Timeout expired for domain: "+ domain)
//chrome.tabs.create({url:"blockingPopUp.html"});
window.open("blockingPopUp.html");
chrome.tabs.remove(tab.id, function() { });
clearInterval(interval);
}
else {
seconds = seconds -1
//alert("Remaining seconds: "+ seconds)
var timestamp = firebase.firestore.Timestamp.fromMillis(seconds*1000)
//alert("doc.id "+doc.id)
chrome.tabs.getSelected(null, function(tab) {
var url = new URL(tab.url)
//alert("Current URL: "+ url);
var domain = url.hostname
chrome.windows.get(tab.windowId, function(chromeWindow) {
if (chromeWindow.state === "minimized") {
// Window is minimized
clearInterval(interval)
} else {
// Window is not minimized (maximized, fullscreen or normal)
if (domain == doc.id){
docRef.set({
Timestamp: timestamp,
});
} else clearInterval(interval)
}
});
});
}
}, 1000);
}
}
}).catch(function(error) {
console.log("Error getting document:", error);
});
}
});
});
*/
chrome.tabs.onActivated.addListener(function(activeInfo) {
//initApp();
//while (uid == undefined);
clearInterval(interval);
//var tabId = info.tabId;
//var windowId = info.windowId;
//alert("info.tabId: "+ info.tabId);
chrome.tabs.getSelected(null, function(tab) {
var url = new URL(tab.url)
if (lastUrl != tab.url){
//alert("LAST URL: "+lastUrl+ " URL: "+tab.url)
//alert("Updated!")
lastUrl = tab.url;
//alert("Current URL: "+ url);
var domain = url.hostname
if (domain.includes('www.')){
domain = domain.replace(/www./, '');
}
//alert("Domain: "+ domain);
//get timer for tab.url, set timeout
var timer = null
db.collection("users").doc(uid).collection("habits").get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
if (doc.exists) {
docRef2 = db.collection("users").doc(uid).collection("habits").doc(doc.id).collection("apps&URLs").doc(domain);
docRef2.get().then(function(doc) {
if (doc.exists) {
docData = doc.data();
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
for (data in doc.data()){
if (data == "PCTimeLeft"){
timer = docData[data];
break;
}
}
//alert("doc.id "+doc.id)
if (timer != undefined){
var seconds = timer.seconds
//myVar = setTimeout(function(){ alert("Timeout set for URL "+ domain); }, seconds);
//alert("timer: "+ seconds);
var interval = setInterval(function(){
if (seconds == 1){
//alert ("Timeout expired for domain: "+ domain)
//chrome.tabs.create({url:"blockingPopUp.html"});
window.open("blockingPopUp.html");
chrome.tabs.remove(tab.id, function() { });
clearInterval(interval);
}
else {
seconds = seconds -1
//alert("Remaining seconds: "+ seconds)
var timestamp = firebase.firestore.Timestamp.fromMillis(seconds*1000)
//alert("doc.id "+doc.id)
chrome.tabs.getSelected(null, function(tab) {
var url = new URL(tab.url)
//alert("Current URL: "+ url);
var domain = url.hostname
chrome.windows.get(tab.windowId, function(chromeWindow) {
if (chromeWindow.state === "minimized") {
// Window is minimized
clearInterval(interval)
} else {
// Window is not minimized (maximized, fullscreen or normal)
if (domain == doc.id){
docRef.set({
Timestamp: timestamp,
});
} else clearInterval(interval)
}
});
});
}
}, 1000);
}
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch(function(error) {
console.log("Error getting document:", error);
})
}
});
});
//
}
});
});
chrome.tabs.onUpdated.addListener(function(id, info, tab) {
//initApp();
//while (uid == undefined);
clearInterval(interval);
//var tabId = info.tabId;
//var windowId = info.windowId;
//alert("info.tabId: "+ info.tabId);
//chrome.tabs.getSelected(null, function(tab) {
var url = new URL(tab.url)
if (lastUrl != tab.url){
//alert("LAST URL: "+lastUrl+ " URL: "+tab.url)
//alert("Updated!")
lastUrl = tab.url;
//alert("Current URL: "+ url);
var domain = url.hostname
if (domain.includes('www.')){
domain = domain.replace(/www./, '');
}
//alert("Domain: "+ domain);
//get timer for tab.url, set timeout
var timer = null
db.collection("users").doc(uid).collection("habits").get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
if (doc.exists) {
docRef2 = db.collection("users").doc(uid).collection("habits").doc(doc.id).collection("apps&URLs").doc(domain);
docRef2.get().then(function(doc) {
if (doc.exists) {
docData = doc.data();
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
for (data in doc.data()){
if (data == "PCTimeLeft"){
timer = docData[data];
break;
}
}
//alert("doc.id "+doc.id)
if (timer != undefined){
var seconds = timer.seconds
//myVar = setTimeout(function(){ alert("Timeout set for URL "+ domain); }, seconds);
//alert("timer: "+ seconds);
var interval = setInterval(function(){
if (seconds == 1){
//alert ("Timeout expired for domain: "+ domain)
//chrome.tabs.create({url:"blockingPopUp.html"});
window.open("blockingPopUp.html");
chrome.tabs.remove(tab.id, function() { });
clearInterval(interval);
}
else {
seconds = seconds -1
//alert("Remaining seconds: "+ seconds)
var timestamp = firebase.firestore.Timestamp.fromMillis(seconds*1000)
//alert("doc.id "+doc.id)
chrome.tabs.getSelected(null, function(tab) {
var url = new URL(tab.url)
//alert("Current URL: "+ url);
var domain = url.hostname
chrome.windows.get(tab.windowId, function(chromeWindow) {
if (chromeWindow.state === "minimized") {
// Window is minimized
clearInterval(interval)
} else {
// Window is not minimized (maximized, fullscreen or normal)
if (domain == doc.id){
docRef.set({
Timestamp: timestamp,
});
} else clearInterval(interval)
}
});
});
}
}, 1000);
}
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch(function(error) {
console.log("Error getting document:", error);
})
}
});
});
//});
}
});
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="main.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<sc