|  | /* *************************************** | 
        
          |  | 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; | 
        
          |  | }) | 
        
          |  | } |