backend-manager 2.4.0 → 2.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backend-manager",
3
- "version": "2.4.0",
3
+ "version": "2.4.3",
4
4
  "description": "Quick tools for developing Firebase functions",
5
5
  "main": "src/manager/index.js",
6
6
  "bin": {
@@ -49,7 +49,7 @@
49
49
  "mocha": "^9.2.2",
50
50
  "moment": "^2.29.4",
51
51
  "node-fetch": "^2.6.7",
52
- "node-powertools": "^0.0.18",
52
+ "node-powertools": "^0.0.19",
53
53
  "npm-api": "^1.0.1",
54
54
  "paypal-server-api": "^0.0.7",
55
55
  "pushid": "^1.0.0",
@@ -67,4 +67,4 @@
67
67
  "src/",
68
68
  "templates/"
69
69
  ]
70
- }
70
+ }
@@ -15,7 +15,7 @@ Module.prototype.main = function () {
15
15
  const payload = self.payload;
16
16
 
17
17
  return new Promise(async function(resolve, reject) {
18
- if (!payload.user.roles.admin) {
18
+ if (!payload.user.roles.admin || !payload.user.roles.blogger) {
19
19
  return reject(assistant.errorManager(`Admin required.`, {code: 401, sentry: false, send: false, log: false}).error)
20
20
  }
21
21
 
@@ -1,4 +1,5 @@
1
1
  const fetch = require('wonderful-fetch');
2
+ const _ = require('lodash');
2
3
 
3
4
  function Module() {
4
5
 
@@ -13,6 +14,21 @@ Module.prototype.main = function () {
13
14
 
14
15
  return new Promise(async function(resolve, reject) {
15
16
 
17
+ // console.log('---self.libraries.admin', self.libraries.admin);
18
+ // console.log('---self.libraries.admin.credential', self.libraries.admin.credential);
19
+ // console.log('---self.libraries.admin.credential.cert()', self.libraries.admin.credential.cert());
20
+ // console.log('---self.libraries.admin.credential.refreshToken()', self.libraries.admin.credential.refreshToken());
21
+ // console.log('---self.libraries.admin.default', self.libraries.admin.default);
22
+ // console.log('---self.libraries.initializedAdmin', self.libraries.initializedAdmin);
23
+ // console.log('---self.libraries.admin.INTERNAL', self.libraries.admin.INTERNAL);
24
+ // console.log('---self.libraries.initializedAdmin.options_.credential', self.libraries.initializedAdmin.options_.credential);
25
+ // console.log('---self.libraries.initializedAdmin.options_.credential.refreshToken', self.libraries.initializedAdmin.options_.credential.refreshToken);
26
+ // console.log('---self.libraries.initializedAdmin.options_.credential.refreshToken', self.libraries.initializedAdmin.options_.credential.refreshToken);
27
+ // console.log('---self.libraries.initializedAdmin.INTERNAL', self.libraries.initializedAdmin.INTERNAL);
28
+ // const powertools = require('node-powertools');
29
+ // console.log('---self.libraries.admin', powertools.stringify(self.libraries.admin));
30
+ // console.log('---self.libraries.initializedAdmin', powertools.stringify(self.libraries.initializedAdmin));
31
+
16
32
  const providers = [
17
33
  { name: 'google.com', prefix: ['id_token'] },
18
34
  { name: 'facebook.com', prefix: ['access_token'] },
@@ -25,12 +41,17 @@ Module.prototype.main = function () {
25
41
  ]
26
42
  const promises = []
27
43
 
28
- payload.data.payload.firebaseApiKey = payload.data.payload.firebaseApiKey || false;
44
+ payload.data.payload.firebaseApiKey = payload.data.payload.firebaseApiKey || _.get(Manager, 'config.firebaseConfig.apiKey') || false;
29
45
 
30
46
  if (!payload.data.payload.firebaseApiKey) {
31
- return reject(assistant.errorManager(`The <firebaseApiKey> parameter is required.`, {code: 400, sentry: false, send: false, log: false}).error)
47
+ return reject(assistant.errorManager(`The firebaseApiKey parameter is required.`, {code: 400, sentry: false, send: false, log: false}).error)
32
48
  }
33
49
 
50
+ // Default
51
+ payload.response.data.password = true;
52
+
53
+ assistant.log('Checking providers for firebaseApiKey', payload.data.payload.firebaseApiKey);
54
+
34
55
  function request(provider) {
35
56
  return new Promise(function(resolve, reject) {
36
57
  let prefix = '';
@@ -63,9 +84,10 @@ Module.prototype.main = function () {
63
84
  if (error.message.includes('OPERATION_NOT_ALLOWED') || error.message.includes('INVALID_CREDENTIAL_OR_PROVIDER_ID')) {
64
85
  result = false;
65
86
  }
87
+ assistant.log('Provider check', provider.name, error);
66
88
  });
67
89
 
68
- assistant.log('Provider details', provider.name, result);
90
+ assistant.log('Provider response', provider.name, result);
69
91
 
70
92
  payload.response.data[provider.name] = result;
71
93
  } catch (e) {
@@ -90,7 +112,36 @@ Module.prototype.main = function () {
90
112
  await Promise.all(promises)
91
113
  .then(response => {
92
114
  // console.log('--payload.response.data', promises.length, payload.response.data);
93
- return resolve({data: payload.response.data});
115
+
116
+ fetch(`https://us-central1-itw-creative-works.cloudfunctions.net/getApp`, {
117
+ method: 'post',
118
+ response: 'json',
119
+ body: {
120
+ id: Manager.config.app.id,
121
+ }
122
+ })
123
+ .then(response => {
124
+ assistant.log('getApp response', response);
125
+ response.authentication = response.authentication || {};
126
+
127
+ Object.keys(response.authentication)
128
+ .forEach((provider, i) => {
129
+ response.authentication[provider] = response.authentication[provider] || {};
130
+
131
+ if (typeof response.authentication[provider].enabled !== 'undefined') {
132
+ payload.response.data[provider] = false;
133
+ assistant.log(`Overwriting ${provider}...`, {environment: 'development'});
134
+ }
135
+ });
136
+
137
+ })
138
+ .catch(e => {
139
+ assistant.errorManager(`Error getting app data: ${e}`, {sentry: false, send: false, log: true})
140
+ })
141
+ .finally(r => {
142
+ return resolve({data: payload.response.data});
143
+ })
144
+
94
145
  })
95
146
  .catch(e => {
96
147
  return reject(assistant.errorManager(`Failed to check providers: ${e}`, {code: 500, sentry: false, send: false, log: false}).error)
@@ -100,5 +151,4 @@ Module.prototype.main = function () {
100
151
 
101
152
  };
102
153
 
103
-
104
154
  module.exports = Module;
@@ -0,0 +1,92 @@
1
+ const decode = require('jwt-decode')
2
+ const _ = require('lodash')
3
+ const fetch = require('wonderful-fetch')
4
+
5
+ function OAuth2() {
6
+ const self = this;
7
+ self.provider = 'discord';
8
+ self.name = 'Discord';
9
+ self.urls = {
10
+ // var oauthURL = 'https://discord.com/api/oauth2/authorize?client_id=701375931918581810&redirect_uri=URL&response_type=code&scope=identify';
11
+
12
+ authorize: 'https://discord.com/api/oauth2/authorize',
13
+ tokenize: 'https://discord.com/api/oauth2/token',
14
+ status: ''
15
+ }
16
+ }
17
+
18
+ OAuth2.prototype.buildUrl = function (state, url) {
19
+ const self = this;
20
+
21
+ return new Promise(function(resolve, reject) {
22
+ if (state === 'authorize') {
23
+ // do something with url
24
+ return resolve()
25
+ } else {
26
+ return resolve()
27
+ }
28
+ });
29
+ };
30
+
31
+ OAuth2.prototype.verifyIdentity = function (tokenizeResult) {
32
+ const self = this;
33
+ const Manager = self.Manager;
34
+
35
+ return new Promise(function(resolve, reject) {
36
+ const decoded = decode(tokenizeResult.id_token);
37
+
38
+ // console.log('---decoded', decoded);
39
+
40
+ // Check if exists
41
+ Manager.libraries.admin.firestore().collection(`users`)
42
+ .where(`oauth2.${self.provider}.identity.email`, '==', decoded.email)
43
+ .get()
44
+ .then(async (snap) => {
45
+ if (snap.size === 0) {
46
+ return resolve(decoded);
47
+ } else {
48
+ return reject(new Error(`This ${self.name} account is already connected to a ${Manager.config.brand.name} account`));
49
+ }
50
+ })
51
+ .catch((e) => {
52
+ return reject(e);
53
+ });
54
+
55
+ });
56
+ };
57
+
58
+ // OAuth2.prototype.verifyConnection = function (newUrl, token) {
59
+ // const self = this;
60
+ // const Manager = self.Manager;
61
+ //
62
+ // return new Promise(function(resolve, reject) {
63
+ //
64
+ // fetch(newUrl, {
65
+ // method: 'post',
66
+ // timeout: 60000,
67
+ // response: 'json',
68
+ // tries: 1,
69
+ // log: true,
70
+ // cacheBreaker: false,
71
+ // body: {
72
+ // id_token: token,
73
+ // }
74
+ // })
75
+ // .then(json => {
76
+ // // console.log('---json', json);
77
+ // return resolve('connected');
78
+ // })
79
+ // .catch(e => {
80
+ // try {
81
+ // const parsed = JSON.parse(e.message);
82
+ // return reject(new Error(`${parsed.error}: ${parsed.error_description}`))
83
+ // } catch (e2) {
84
+ // return reject(e);
85
+ // }
86
+ // })
87
+ //
88
+ // });
89
+ // };
90
+
91
+
92
+ module.exports = OAuth2;
@@ -1,12 +1,16 @@
1
1
  const decode = require('jwt-decode')
2
+ const _ = require('lodash')
3
+ const fetch = require('wonderful-fetch')
2
4
 
3
5
  function OAuth2() {
4
6
  const self = this;
5
- self.service = 'google';
7
+ self.provider = 'google';
6
8
  self.name = 'Google';
7
9
  self.urls = {
8
10
  authorize: 'https://accounts.google.com/o/oauth2/v2/auth',
9
11
  tokenize: 'https://oauth2.googleapis.com/token',
12
+ // status: 'https://oauth2.googleapis.com/tokeninfo?id_token={token}'
13
+ status: 'https://oauth2.googleapis.com/tokeninfo'
10
14
  }
11
15
  }
12
16
 
@@ -34,7 +38,7 @@ OAuth2.prototype.verifyIdentity = function (tokenizeResult) {
34
38
 
35
39
  // Check if exists
36
40
  Manager.libraries.admin.firestore().collection(`users`)
37
- .where(`oauth2.${self.service}.identity.email`, '==', decoded.email)
41
+ .where(`oauth2.${self.provider}.identity.email`, '==', decoded.email)
38
42
  .get()
39
43
  .then(async (snap) => {
40
44
  if (snap.size === 0) {
@@ -50,4 +54,38 @@ OAuth2.prototype.verifyIdentity = function (tokenizeResult) {
50
54
  });
51
55
  };
52
56
 
57
+ // OAuth2.prototype.verifyConnection = function (newUrl, token) {
58
+ // const self = this;
59
+ // const Manager = self.Manager;
60
+ //
61
+ // return new Promise(function(resolve, reject) {
62
+ //
63
+ // fetch(newUrl, {
64
+ // method: 'post',
65
+ // timeout: 60000,
66
+ // response: 'json',
67
+ // tries: 1,
68
+ // log: true,
69
+ // cacheBreaker: false,
70
+ // body: {
71
+ // id_token: token,
72
+ // }
73
+ // })
74
+ // .then(json => {
75
+ // // console.log('---json', json);
76
+ // return resolve('connected');
77
+ // })
78
+ // .catch(e => {
79
+ // try {
80
+ // const parsed = JSON.parse(e.message);
81
+ // return reject(new Error(`${parsed.error}: ${parsed.error_description}`))
82
+ // } catch (e2) {
83
+ // return reject(e);
84
+ // }
85
+ // })
86
+ //
87
+ // });
88
+ // };
89
+
90
+
53
91
  module.exports = OAuth2;
@@ -28,7 +28,7 @@ Module.prototype.main = function () {
28
28
  ? `http://localhost:4000/oauth2`
29
29
  : `${Manager.config.brand.url}/oauth2`
30
30
  self.oauth2 = null;
31
- self.omittedPayloadFields = ['redirect', 'referrer', 'service', 'state'];
31
+ self.omittedPayloadFields = ['redirect', 'referrer', 'provider', 'state'];
32
32
 
33
33
  // self.ultimateJekyllOAuth2Url = `${Manager.config.brand.url}/oauth2`;
34
34
 
@@ -42,19 +42,22 @@ Module.prototype.main = function () {
42
42
  ? (assistant.meta.environment === 'development' ? `http://localhost:4000/oauth2` : `${Manager.config.brand.url}/oauth2`)
43
43
  : payload.data.payload.referrer
44
44
 
45
- payload.data.payload.service = payload.data.payload.service || '';
45
+ payload.data.payload.provider = payload.data.payload.provider || '';
46
46
  payload.data.payload.state = payload.data.payload.state || 'authorize'; // authorize, tokenize, deauthorize, refresh, get
47
+ payload.data.payload.redirect_uri = payload.data.payload.redirect_uri
48
+ ? payload.data.payload.redirect_uri
49
+ : payload.data.payload.referrer;
47
50
 
48
51
  // payload.data.payload.parameters = payload.data.payload.parameters || {}
49
52
 
50
53
  // payload.data.payload.client_id = payload.data.payload.client_id;
51
54
  // payload.data.payload.scope = payload.data.payload.scope;
52
- // payload.data.payload.redirect_uri = payload.data.payload.redirect_uri;
53
55
 
54
56
  let newUrl;
57
+ const client_id = _.get(Manager.config, `oauth2.${payload.data.payload.provider}.client_id`);
55
58
  const state = {
56
59
  code: 'success',
57
- service: payload.data.payload.service,
60
+ provider: payload.data.payload.provider,
58
61
  authenticationToken: payload.data.authenticationToken,
59
62
  serverUrl: `${Manager.project.functionsUrl}/bm_api`,
60
63
  referrer: payload.data.payload.referrer,
@@ -64,7 +67,7 @@ Module.prototype.main = function () {
64
67
  assistant.log('OAuth2 payload', payload.data.payload);
65
68
 
66
69
  try {
67
- self.oauth2 = new (require(`./oauth2/${payload.data.payload.service}.js`))();
70
+ self.oauth2 = new (require(`./oauth2/${payload.data.payload.provider}.js`))();
68
71
  self.oauth2.parent = self;
69
72
  self.oauth2.Manager = self.Manager;
70
73
 
@@ -75,8 +78,11 @@ Module.prototype.main = function () {
75
78
  newUrl = new URL(newUrl)
76
79
 
77
80
  if (payload.data.payload.state === 'authorize') {
81
+ if (!client_id) {
82
+ throw new Error(`Missing client_id for ${payload.data.payload.provider} provider`)
83
+ }
78
84
  newUrl.searchParams.set('state', JSON.stringify(state));
79
- newUrl.searchParams.set('client_id', _.get(Manager.config, `oauth2.${payload.data.payload.service}.client_id`));
85
+ newUrl.searchParams.set('client_id', client_id);
80
86
  newUrl.searchParams.set('scope', payload.data.payload.scope);
81
87
  newUrl.searchParams.set('redirect_uri', self.ultimateJekyllOAuth2Url);
82
88
 
@@ -111,6 +117,10 @@ Module.prototype.main = function () {
111
117
  self.processState_deauthorize(newUrl)
112
118
  .then(r => {resolve(r)})
113
119
  .catch(e => {reject(e)})
120
+ } else if (payload.data.payload.state === 'status') {
121
+ self.processState_status(newUrl)
122
+ .then(r => {resolve(r)})
123
+ .catch(e => {reject(e)})
114
124
  }
115
125
  })
116
126
  .catch(e => {
@@ -132,7 +142,7 @@ Module.prototype.processState_authorize = function (newUrl) {
132
142
 
133
143
  return resolve({
134
144
  data: {
135
- authorizationUrl: finalUrl,
145
+ url: finalUrl,
136
146
  },
137
147
  redirect: payload.data.payload.redirect ? finalUrl : null
138
148
  });
@@ -150,8 +160,8 @@ Module.prototype.processState_tokenize = function (newUrl) {
150
160
  const finalUrl = newUrl.toString();
151
161
 
152
162
  const body = {
153
- client_id: _.get(Manager.config, `oauth2.${payload.data.payload.service}.client_id`),
154
- client_secret: _.get(Manager.config, `oauth2.${payload.data.payload.service}.client_secret`),
163
+ client_id: _.get(Manager.config, `oauth2.${payload.data.payload.provider}.client_id`),
164
+ client_secret: _.get(Manager.config, `oauth2.${payload.data.payload.provider}.client_secret`),
155
165
  grant_type: 'authorization_code',
156
166
  redirect_uri: self.ultimateJekyllOAuth2Url,
157
167
  code: payload.data.payload.code,
@@ -195,7 +205,7 @@ Module.prototype.processState_tokenize = function (newUrl) {
195
205
  const storeResponse = await self.libraries.admin.firestore().doc(`users/${payload.user.auth.uid}`)
196
206
  .set({
197
207
  oauth2: {
198
- [payload.data.payload.service]: {
208
+ [payload.data.payload.provider]: {
199
209
  code: _.omit(
200
210
  _.merge({}, payload.data.payload),
201
211
  self.omittedPayloadFields,
@@ -236,7 +246,7 @@ Module.prototype.processState_deauthorize = function () {
236
246
  self.libraries.admin.firestore().doc(`users/${payload.user.auth.uid}`)
237
247
  .set({
238
248
  oauth2: {
239
- [payload.data.payload.service]: {},
249
+ [payload.data.payload.provider]: {},
240
250
  updated: {
241
251
  timestamp: assistant.meta.startTime.timestamp,
242
252
  timestampUNIX: assistant.meta.startTime.timestampUNIX,
@@ -254,7 +264,81 @@ Module.prototype.processState_deauthorize = function () {
254
264
  });
255
265
  };
256
266
 
267
+ Module.prototype.processState_status = function (newUrl) {
268
+ const self = this;
269
+ const Manager = self.Manager;
270
+ const Api = self.Api;
271
+ const assistant = self.assistant;
272
+ const payload = self.payload;
273
+
274
+ return new Promise(async function(resolve, reject) {
275
+ const finalUrl = newUrl.toString();
276
+
277
+ payload.data.payload.removeInvalidTokens = typeof payload.data.payload.removeInvalidTokens === 'undefined'
278
+ ? true
279
+ : payload.data.payload.removeInvalidTokens;
280
+
281
+ function _remove() {
282
+ return new Promise(function(resolve, reject) {
283
+ if (!payload.data.payload.removeInvalidTokens) {
284
+ return resolve();
285
+ }
286
+
287
+ Manager.libraries.admin.firestore().doc(`users/${payload.user.auth.uid}`)
288
+ .set({
289
+ oauth2: {
290
+ [payload.data.payload.provider]: {},
291
+ updated: {
292
+ timestamp: assistant.meta.startTime.timestamp,
293
+ timestampUNIX: assistant.meta.startTime.timestampUNIX,
294
+ }
295
+ }
296
+ }, { merge: true })
297
+ .then(async () => {
298
+ assistant.log(`Removed disconnected token for user: ${payload.user.auth.uid}`)
299
+ })
300
+ .catch((e) => e)
301
+ .finally(() => {
302
+ return resolve();
303
+ })
304
+ });
305
+ }
257
306
 
307
+ Manager.libraries.admin.firestore().doc(`users/${payload.user.auth.uid}`)
308
+ .get()
309
+ .then(async (doc) => {
310
+ const data = doc.data();
311
+ const token = _.get(data, `oauth2.${payload.data.payload.provider}.token.refresh_token`, '');
312
+ // const token = _.get(data, `oauth2.${payload.data.payload.provider}.token.access_token`, '');
313
+ if (!token) {
314
+ return resolve({
315
+ data: {status: 'disconnected'}
316
+ });
317
+ } else if (!self.oauth2.verifyConnection) {
318
+ return resolve({
319
+ data: {status: 'connected'}
320
+ });
321
+ } else {
322
+ // self.oauth2.verifyConnection(finalUrl.replace(/{token}/ig, encodeURIComponent(token)), token)
323
+ self.oauth2.verifyConnection(finalUrl.replace(/{token}/ig, token), token)
324
+ .then(async (status) => {
325
+ if (status === 'disconnected') {
326
+ await _remove();
327
+ }
328
+ return resolve({
329
+ data: {status: status},
330
+ })
331
+ })
332
+ .catch(async (e) => {
333
+ await _remove();
334
+ return resolve({
335
+ data: {status: 'error', error: e.message},
336
+ })
337
+ })
338
+ }
339
+ })
340
+ });
341
+ };
258
342
 
259
343
 
260
344
  Module.prototype.processState_template = function (newUrl) {
@@ -269,11 +353,13 @@ Module.prototype.processState_template = function (newUrl) {
269
353
 
270
354
  return resolve({
271
355
  data: {
272
- authorizationUrl: finalUrl,
356
+ url: finalUrl,
273
357
  },
274
358
  redirect: payload.data.payload.redirect ? finalUrl : null
275
359
  });
276
360
  });
277
361
  };
278
362
 
363
+
364
+
279
365
  module.exports = Module;
@@ -22,5 +22,15 @@
22
22
  },
23
23
  "google_analytics": {
24
24
  "id": "UA-123456789-1"
25
+ },
26
+ "firebaseConfig": {
27
+ "apiKey": "123-456",
28
+ "authDomain": "PROJECT-ID.firebaseapp.com",
29
+ "databaseURL": "https://PROJECT-ID.firebaseio.com",
30
+ "projectId": "PROJECT-ID",
31
+ "storageBucket": "PROJECT-ID.appspot.com",
32
+ "messagingSenderId": "123",
33
+ "appId": "1:123:web:456",
34
+ "measurementId": "G-0123456789"
25
35
  }
26
36
  }