Skip to content

Commit 677cf79

Browse files
committed
Use node-fetch for promises in HTTP requests.
1 parent 4e59f87 commit 677cf79

File tree

2 files changed

+81
-108
lines changed

2 files changed

+81
-108
lines changed

functions/composer-storage-trigger/index.js

Lines changed: 79 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@
1414
* limitations under the License.
1515
*/
1616

17+
// [START composer_trigger]
1718
'use strict';
1819

19-
// [START composer_trigger]
20+
const fetch = require('node-fetch');
21+
const FormData = require('form-data');
22+
2023
/**
2124
* Triggered from a message on a Cloud Storage bucket.
2225
*
@@ -42,105 +45,84 @@ exports.triggerDag = function triggerDag (event, callback) {
4245
const DAG_NAME = 'composer_sample_trigger_response_dag';
4346

4447
// Other constants
45-
const WEBSERVER_URL = 'https://' + WEBSERVER_ID +
46-
'.appspot.com/api/experimental/dags/' + DAG_NAME + '/dag_runs';
48+
const WEBSERVER_URL = `https://${WEBSERVER_ID}.appspot.com/api/experimental/dags/${DAG_NAME}/dag_runs`;
4749
const USER_AGENT = 'gcf-event-trigger';
4850
const BODY = {'conf': JSON.stringify(event.data)};
4951

5052
// Make the request
51-
authorizeIap(
52-
CLIENT_ID, PROJECT_ID, USER_AGENT,
53-
function iapAuthorizationCallback (err, jwt, idToken) {
54-
if (err) {
55-
return callback(err);
56-
}
57-
makeIapPostRequest(
58-
WEBSERVER_URL, BODY, idToken, USER_AGENT, jwt, callback);
59-
});
53+
authorizeIap(CLIENT_ID, PROJECT_ID, USER_AGENT)
54+
.then(function iapAuthorizationCallback (iap) {
55+
makeIapPostRequest(WEBSERVER_URL, BODY, iap.idToken, USER_AGENT, iap.jwt);
56+
})
57+
.then(_ => callback(null))
58+
.catch(callback);
6059
};
6160

6261
/**
6362
* @param {string} clientId The client id associated with the Composer webserver application.
6463
* @param {string} projectId The id for the project containing the Cloud Function.
6564
* @param {string} userAgent The user agent string which will be provided with the webserver request.
66-
* @param {!Function} callback A callback accepting error, jwt, and idToken arguments.
6765
*/
68-
function authorizeIap (clientId, projectId, userAgent, callback) {
69-
const request = require('request');
66+
function authorizeIap (clientId, projectId, userAgent) {
67+
const SERVICE_ACCOUNT = `${projectId}@appspot.gserviceaccount.com`;
68+
const JWT_HEADER = Buffer.from(JSON.stringify({alg: 'RS256', typ: 'JWT'}))
69+
.toString('base64');
7070

71-
const SERVICE_ACCOUNT = [projectId, '@appspot.gserviceaccount.com'].join('');
71+
var jwt = '';
72+
var jwtClaimset = '';
7273

73-
var options = {
74-
url: [
75-
'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/',
76-
SERVICE_ACCOUNT, '/token'
77-
].join(''),
78-
headers: {'User-Agent': userAgent, 'Metadata-Flavor': 'Google'}
79-
};
80-
// Obtain an Oauth2 access token for the appspot service account
81-
request(options, function obtainAccessTokenCallback (err, res, body) {
82-
if (err) {
83-
return callback(err);
84-
}
85-
if (body.error) {
86-
return callback(body);
87-
}
88-
var tokenResponse = JSON.parse(body);
89-
var accessToken = tokenResponse.access_token;
90-
var jwtHeader = Buffer.from(JSON.stringify({alg: 'RS256', typ: 'JWT'}))
91-
.toString('base64');
92-
var iat = Math.floor(new Date().getTime() / 1000);
93-
var claims = {
94-
iss: SERVICE_ACCOUNT,
95-
aud: 'https://www.googleapis.com/oauth2/v4/token',
96-
iat: iat,
97-
exp: iat + 60,
98-
target_audience: clientId
99-
};
100-
var jwtClaimset = Buffer.from(JSON.stringify(claims)).toString('base64');
101-
var toSign = [jwtHeader, jwtClaimset].join('.');
102-
var options = {
103-
url: [
104-
'https://iam.googleapis.com/v1/projects/', projectId,
105-
'/serviceAccounts/', SERVICE_ACCOUNT, ':signBlob'
106-
].join(''),
107-
method: 'POST',
108-
json: {'bytesToSign': Buffer.from(toSign).toString('base64')},
109-
headers: {
110-
'User-Agent': userAgent,
111-
'Authorization': ['Bearer', accessToken].join(' ')
112-
}
113-
};
74+
// Obtain an Oauth2 access token for the appspot service account
75+
return fetch(
76+
`http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/${SERVICE_ACCOUNT}/token`,
77+
{
78+
headers: {'User-Agent': userAgent, 'Metadata-Flavor': 'Google'}
79+
})
80+
.then(res => res.json())
81+
.then(function obtainAccessTokenCallback (tokenResponse) {
82+
var accessToken = tokenResponse.access_token;
83+
var iat = Math.floor(new Date().getTime() / 1000);
84+
var claims = {
85+
iss: SERVICE_ACCOUNT,
86+
aud: 'https://www.googleapis.com/oauth2/v4/token',
87+
iat: iat,
88+
exp: iat + 60,
89+
target_audience: clientId
90+
};
91+
jwtClaimset = Buffer.from(JSON.stringify(claims)).toString('base64');
92+
var toSign = [JWT_HEADER, jwtClaimset].join('.');
93+
94+
return fetch(
95+
`https://iam.googleapis.com/v1/projects/${projectId}/serviceAccounts/${SERVICE_ACCOUNT}:signBlob`,
96+
{
97+
method: 'POST',
98+
body: JSON.stringify({'bytesToSign': Buffer.from(toSign).toString('base64')}),
99+
headers: {
100+
'User-Agent': userAgent,
101+
'Authorization': `Bearer ${accessToken}`
102+
}
103+
});
104+
})
105+
.then(res => res.json())
106+
.then(function signJsonClaimCallback (body) {
114107
// Request service account signature on header and claimset
115-
request(options, function signJsonClaimCallback (err, res, body) {
116-
if (err) {
117-
return callback(err);
118-
}
119-
if (body.error) {
120-
return callback(body);
121-
}
122108
var jwtSignature = body.signature;
123-
var jwt = [jwtHeader, jwtClaimset, jwtSignature].join('.');
124-
var options = {
125-
url: 'https://www.googleapis.com/oauth2/v4/token',
126-
form: {
127-
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
128-
assertion: jwt
129-
}
109+
jwt = [JWT_HEADER, jwtClaimset, jwtSignature].join('.');
110+
var form = new FormData();
111+
form.append('grant_type', 'urn:ietf:params:oauth:grant-type:jwt-bearer');
112+
form.append('assertion', jwt);
113+
return fetch(
114+
'https://www.googleapis.com/oauth2/v4/token', {
115+
method: 'POST',
116+
body: form
117+
});
118+
})
119+
.then(res => res.json())
120+
.then(function returnJwt (body) {
121+
return {
122+
jwt: jwt,
123+
idToken: body.id_token
130124
};
131-
// Request oauth id token with jwt header, claims, and signature
132-
request.post(options, function getIdTokenCallback (err, res, body) {
133-
if (err) {
134-
return callback(err);
135-
}
136-
if (body.error) {
137-
return callback(body);
138-
}
139-
var idToken = JSON.parse(body).id_token;
140-
callback(null, jwt, idToken);
141-
});
142125
});
143-
});
144126
}
145127

146128
/**
@@ -149,35 +131,25 @@ function authorizeIap (clientId, projectId, userAgent, callback) {
149131
* @param {string} idToken Bearer token used to authorize the iap request.
150132
* @param {string} userAgent The user agent to identify the requester.
151133
* @param {string} jwt A Json web token used to authenticate the request.
152-
* @param {!Function} callback The Cloud Functions callback.
153134
*/
154-
function makeIapPostRequest (url, body, idToken, userAgent, jwt, callback) {
155-
const request = require('request');
156-
157-
request.post(
158-
{
159-
url: url,
160-
form: {
161-
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
162-
assertion: jwt
163-
}
164-
},
165-
function makeIapPostRequestCallback (err, res) {
166-
if (err) {
167-
return callback(err);
168-
}
135+
function makeIapPostRequest (url, body, idToken, userAgent, jwt) {
136+
var form = new FormData();
137+
form.append('grant_type', 'urn:ietf:params:oauth:grant-type:jwt-bearer');
138+
form.append('assertion', jwt);
169139

170-
var options = {
171-
url: url,
140+
return fetch(
141+
url, {
142+
method: 'POST',
143+
body: form
144+
})
145+
.then(function makeIapPostRequestCallback () {
146+
return fetch(url, {
147+
method: 'POST',
172148
headers: {
173149
'User-Agent': userAgent,
174-
'Authorization': ['Bearer', idToken].join(' ')
150+
'Authorization': `Bearer ${idToken}`
175151
},
176-
method: 'POST',
177-
json: body
178-
};
179-
request(options, function (err, res, body) {
180-
callback(err);
152+
body: JSON.stringify(body)
181153
});
182154
});
183155
}

functions/composer-storage-trigger/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
"name": "nodejs-docs-samples-functions-composer-storage-trigger",
33
"version": "0.0.1",
44
"dependencies": {
5-
"request": ">=2.83"
5+
"form-data": "^2.3.2",
6+
"node-fetch": "^2.2.0"
67
},
78
"engines": {
89
"node": ">=4.3.2"

0 commit comments

Comments
 (0)