|
/* *************************************** |
|
firebase_project/functions/index.js |
|
*************************************** */ |
|
|
|
// Sample code for executing AppScript |
|
const functions = require('firebase-functions'); |
|
const axios = require('axios'); |
|
const querystring = require('querystring'); |
|
|
|
const appscript = require("./appscript"); |
|
|
|
exports.main = { |
|
execAppScript: functions.https.onRequest((req,res) => {execAppScript(req,res)}), |
|
oauthCallback: functions.https.onRequest((req,res) => {oauthCallback(req,res)}) |
|
} |
|
|
|
exports.appscript = appscript; |
|
|
|
|
|
/* |
|
Callback URLs for OAuth result |
|
*/ |
|
const oauthCallbackUrl = "https://" + |
|
process.env.GCLOUD_PROJECT + |
|
".firebaseapp.com/oauthcallback"; |
|
|
|
/* |
|
OAuth 2.0 client IDs |
|
1. visit https://console.developers.google.com |
|
2. select your project |
|
3. select APIs & Services > Credentials |
|
4. create a OAuth client ID for Web application if you don't have one |
|
5. select your Web client ID, and add your OAuth callback URI |
|
(e.g. "https://<your-project-name>.firebaseapp.com/oauthcallback" ) |
|
6. download the JSON file of the client |
|
7. rename and save it to the same folder as your code files |
|
*/ |
|
const keys = require('./xxxxxxxxxxxxxxxxx.json'); |
|
|
|
|
|
/* |
|
scopes required to execute the script |
|
1. In the script editor, select "File" > "Project properties" |
|
2. Select the "Scopes" tab |
|
3. Add all scopes to the list |
|
*/ |
|
const scriptScopes = [ |
|
"https://www.googleapis.com/auth/userinfo.email" |
|
]; |
|
|
|
|
|
function execAppScript(request, response) { |
|
|
|
request.allparams = Object.assign(request.query, request.body); |
|
console.log(request.path); |
|
console.log("params", request.allparams); |
|
//console.log("headers", request.headers); |
|
|
|
var accessToken = request.allparams.access_token; |
|
var fnName = request.allparams["function"]; |
|
var fnParams = request.allparams["params"]; |
|
|
|
if (!fnName) { |
|
fnName = "hello_world"; |
|
fnParams = ["Beep beep beep!"]; |
|
} |
|
|
|
if (!accessToken) { |
|
|
|
var opts = { |
|
redirect_uri : oauthCallbackUrl, |
|
response_type: "code", |
|
client_id: keys.web.client_id, |
|
scope: scriptScopes.join(" "), |
|
access_type: "offline", |
|
state: JSON.stringify( { "function":fnName, "params": fnParams } ) |
|
}; |
|
var authUrl = "https://accounts.google.com/o/oauth2/v2/auth?" + |
|
querystring.stringify(opts); |
|
response.writeHead(307, { 'Location': authUrl }); |
|
response.end(); |
|
|
|
} else { |
|
|
|
appscript.run(accessToken, fnName, fnParams) |
|
.then(res => { |
|
response.set("access_token", accessToken) |
|
response.set("Access-Control-Allow-Origin", "*"); |
|
response.set("Access-Control-Allow-Methods", "GET, POST"); |
|
response.status(200).end(res.data); |
|
}) |
|
.catch(err => { |
|
// handle axios errors |
|
if (err.response) { |
|
console.error(err.response.data); |
|
console.error(err.response.status); |
|
console.error(err.response.headers); |
|
} else if (err.request) { |
|
console.error(err.request) |
|
} else { |
|
console.error("Error", err.message); |
|
} |
|
console.error(err.config); |
|
response.status(500).end(); |
|
}); |
|
} |
|
|
|
} |
|
|
|
|
|
function oauthCallback (request, response) { |
|
|
|
request.allparams = Object.assign(request.query, request.body); |
|
console.log(request.path); |
|
console.log("params", request.allparams); |
|
//console.log("headers", request.headers); |
|
|
|
var auth_code = request.allparams.code; |
|
|
|
if (!auth_code) { |
|
console.error("no auth code"); |
|
response.status(500).end(); |
|
return null; |
|
} |
|
|
|
var fnName; |
|
var fnParams; |
|
|
|
try { |
|
var state = JSON.parse( request.allparams.state ); |
|
fnName = state["function"]; |
|
fnParams = state["params"]; |
|
} catch (err) { |
|
console.error("JSON parse error"); |
|
response.status(500).end(); |
|
return null; |
|
} |
|
|
|
if (!fnName) { |
|
fnName = "hello_world"; |
|
fnParams = ["Honk honk honk!"]; |
|
} |
|
|
|
// Exchange authentication code for access token |
|
return getAccessToken(auth_code) |
|
.then(accessToken => { |
|
return appscript.run(accessToken, fnName, fnParams) |
|
}) |
|
.then(res => { |
|
response.set("access_token", res.accessToken) |
|
response.set("Access-Control-Allow-Origin", "*"); |
|
response.set("Access-Control-Allow-Methods", "GET, POST"); |
|
response.status(res.status).end(res.data); |
|
}) |
|
.catch(err => { |
|
// handle axios errors |
|
if (err.response) { |
|
console.error(err.response.data); |
|
console.error(err.response.status); |
|
console.error(err.response.headers); |
|
} else if (err.request) { |
|
console.error(err.request) |
|
} else { |
|
console.error("Error", err.message); |
|
} |
|
console.error(err.config); |
|
response.status(500).end(); |
|
}); |
|
|
|
} |
|
|
|
|
|
function getAccessToken(auth_code) { |
|
console.log("token exchange, send", auth_code); |
|
|
|
const url = "https://www.googleapis.com/oauth2/v4/token"; |
|
const config = { timeout: 10000 }; |
|
const body = { |
|
code: auth_code, |
|
redirect_uri : oauthCallbackUrl, |
|
client_id: keys.web.client_id, |
|
client_secret: keys.web.client_secret, |
|
scope: "", |
|
grant_type: "authorization_code" |
|
}; |
|
|
|
return axios |
|
.post(url, querystring.stringify(body), config) |
|
.then(res => { |
|
console.log("token exchange, get", res.data); |
|
return res.data.access_token; |
|
}) |
|
} |