From e27a6578ee2fd39f48850d6361ae5388843d599e Mon Sep 17 00:00:00 2001 From: Patrick Hieber Date: Sun, 6 Jan 2019 17:55:51 +0100 Subject: [PATCH 01/12] feat(api): Update to latest version of googleapis googleapis dependency updated to v36.0.0 --- google.js | 10 +++++----- package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/google.js b/google.js index b6391d5..dc9e174 100644 --- a/google.js +++ b/google.js @@ -14,15 +14,15 @@ module.exports = function(RED) { }; } - var google = require('googleapis'); - var discovery = google.discovery('v1'); + var { google } = require('googleapis'); + var discovery = google.discovery({ version: 'v1' }); RED.httpAdmin.get('/google/apis', function(req, res) { discovery.apis.list({ fields: "items(name,version)" }, function(err, data) { var response = []; - data.items.forEach(function(v) { + data.data.items.forEach(function(v) { response.push(encodeAPI(v.name, v.version)); }); response.sort(); @@ -63,10 +63,10 @@ module.exports = function(RED) { } } - processResources(data); + processResources(data.data); response.operations.sort(); - response.scopes = Object.keys(data.auth.oauth2.scopes); + response.scopes = Object.keys(data.data.auth.oauth2.scopes); res.json(response); diff --git a/package.json b/package.json index 459e5ee..3775cdd 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.2.0", "description": "Node-RED node for Google APIs call.", "dependencies": { - "googleapis": "^15.0.0" + "googleapis": "^36.0.0" }, "license": "MIT", "keywords": [ From e3c5f6f85d9ca366077cd5adba9a3bb72d827e41 Mon Sep 17 00:00:00 2001 From: Patrick Hieber Date: Mon, 7 Jan 2019 12:15:00 +0100 Subject: [PATCH 02/12] feat(oauth2): Add OAuth2 authentication Replace the JWT Service authentication with OAuth2 Authentication. --- google-auth.html | 137 +++++++++++++++++++++++++++++++++++++++++++++++ google-auth.js | 98 +++++++++++++++++++++++++++++++++ google.html | 49 +---------------- google.js | 89 +++++++++++------------------- package.json | 3 +- 5 files changed, 271 insertions(+), 105 deletions(-) create mode 100644 google-auth.html create mode 100644 google-auth.js diff --git a/google-auth.html b/google-auth.html new file mode 100644 index 0000000..43d99b5 --- /dev/null +++ b/google-auth.html @@ -0,0 +1,137 @@ + + + diff --git a/google-auth.js b/google-auth.js new file mode 100644 index 0000000..09457a6 --- /dev/null +++ b/google-auth.js @@ -0,0 +1,98 @@ +module.exports = function(RED) { + "use strict"; + const crypto = require("crypto"); + const url = require('url'); + const { google } = require('googleapis'); + + function GoogleNode(n) { + RED.nodes.createNode(this,n); + this.displayName = n.displayName; + this.scopes = n.scopes; + } + RED.nodes.registerType("google-credentials",GoogleNode,{ + credentials: { + displayName: {type:"text"}, + clientId: {type:"text"}, + clientSecret: {type:"password"}, + accessToken: {type:"password"}, + refreshToken: {type:"password"}, + expireTime: {type:"password"} + } + }); + + RED.httpAdmin.get('/google-credentials/auth', function(req, res){ + console.log('google-credentials/auth'); + if (!req.query.clientId || !req.query.clientSecret || + !req.query.id || !req.query.callback) { + res.send(400); + return; + } + const node_id = req.query.id; + const callback = req.query.callback; + const credentials = { + clientId: req.query.clientId, + clientSecret: req.query.clientSecret + }; + const scopes = req.query.scopes; + + const csrfToken = crypto.randomBytes(18).toString('base64').replace(/\//g, '-').replace(/\+/g, '_'); + credentials.csrfToken = csrfToken; + credentials.callback = callback; + res.cookie('csrf', csrfToken); + res.redirect(url.format({ + protocol: 'https', + hostname: 'accounts.google.com', + pathname: '/o/oauth2/auth', + query: { + access_type: 'offline', + approval_prompt: 'force', + scope: scopes, + response_type: 'code', + client_id: credentials.clientId, + redirect_uri: callback, + state: node_id + ":" + csrfToken, + } + })); + RED.nodes.addCredentials(node_id, credentials); + }); + + RED.httpAdmin.get('/google-credentials/auth/callback', function(req, res) { + console.log('google-credentials/auth/callback'); + if (req.query.error) { + return res.send("google.error.error", {error: req.query.error, description: req.query.error_description}); + } + var state = req.query.state.split(':'); + var node_id = state[0]; + var credentials = RED.nodes.getCredentials(node_id); + if (!credentials || !credentials.clientId || !credentials.clientSecret) { + console.log("credentials not present?"); + return res.send("google.error.no-credentials"); + } + if (state[1] !== credentials.csrfToken) { + return res.status(401).send("google.error.token-mismatch"); + } + + const oauth2Client = new google.auth.OAuth2( + credentials.clientId, + credentials.clientSecret, + credentials.callback + ); + + oauth2Client.getToken(req.query.code) + .then((value) => { + credentials.accessToken = value.tokens.access_token; + credentials.refreshToken = value.tokens.refresh_token; + credentials.expireTime = value.tokens.expiry_date; + credentials.tokenType = value.tokens.token_type; + credentials.displayName = value.tokens.scope.substr(0, 40); + + delete credentials.csrfToken; + delete credentials.callback; + RED.nodes.addCredentials(node_id, credentials); + res.send('Authorized'); + }) + .catch((error) => { + return res.send('Could not receive tokens'); + }); + }); +}; \ No newline at end of file diff --git a/google.html b/google.html index da484d7..994033b 100644 --- a/google.html +++ b/google.html @@ -1,49 +1,3 @@ - - - -