backend-manager 2.4.1 → 2.4.4

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.1",
3
+ "version": "2.4.4",
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,11 +42,11 @@ 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
47
  payload.data.payload.redirect_uri = payload.data.payload.redirect_uri
48
48
  ? payload.data.payload.redirect_uri
49
- : `${Manager.config.brand.url}/authentication/account`;
49
+ : payload.data.payload.referrer;
50
50
 
51
51
  // payload.data.payload.parameters = payload.data.payload.parameters || {}
52
52
 
@@ -54,9 +54,10 @@ Module.prototype.main = function () {
54
54
  // payload.data.payload.scope = payload.data.payload.scope;
55
55
 
56
56
  let newUrl;
57
+ const client_id = _.get(Manager.config, `oauth2.${payload.data.payload.provider}.client_id`);
57
58
  const state = {
58
59
  code: 'success',
59
- service: payload.data.payload.service,
60
+ provider: payload.data.payload.provider,
60
61
  authenticationToken: payload.data.authenticationToken,
61
62
  serverUrl: `${Manager.project.functionsUrl}/bm_api`,
62
63
  referrer: payload.data.payload.referrer,
@@ -66,7 +67,7 @@ Module.prototype.main = function () {
66
67
  assistant.log('OAuth2 payload', payload.data.payload);
67
68
 
68
69
  try {
69
- self.oauth2 = new (require(`./oauth2/${payload.data.payload.service}.js`))();
70
+ self.oauth2 = new (require(`./oauth2/${payload.data.payload.provider}.js`))();
70
71
  self.oauth2.parent = self;
71
72
  self.oauth2.Manager = self.Manager;
72
73
 
@@ -77,8 +78,11 @@ Module.prototype.main = function () {
77
78
  newUrl = new URL(newUrl)
78
79
 
79
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
+ }
80
84
  newUrl.searchParams.set('state', JSON.stringify(state));
81
- newUrl.searchParams.set('client_id', _.get(Manager.config, `oauth2.${payload.data.payload.service}.client_id`));
85
+ newUrl.searchParams.set('client_id', client_id);
82
86
  newUrl.searchParams.set('scope', payload.data.payload.scope);
83
87
  newUrl.searchParams.set('redirect_uri', self.ultimateJekyllOAuth2Url);
84
88
 
@@ -113,6 +117,10 @@ Module.prototype.main = function () {
113
117
  self.processState_deauthorize(newUrl)
114
118
  .then(r => {resolve(r)})
115
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)})
116
124
  }
117
125
  })
118
126
  .catch(e => {
@@ -134,7 +142,7 @@ Module.prototype.processState_authorize = function (newUrl) {
134
142
 
135
143
  return resolve({
136
144
  data: {
137
- authorizationUrl: finalUrl,
145
+ url: finalUrl,
138
146
  },
139
147
  redirect: payload.data.payload.redirect ? finalUrl : null
140
148
  });
@@ -152,8 +160,8 @@ Module.prototype.processState_tokenize = function (newUrl) {
152
160
  const finalUrl = newUrl.toString();
153
161
 
154
162
  const body = {
155
- client_id: _.get(Manager.config, `oauth2.${payload.data.payload.service}.client_id`),
156
- 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`),
157
165
  grant_type: 'authorization_code',
158
166
  redirect_uri: self.ultimateJekyllOAuth2Url,
159
167
  code: payload.data.payload.code,
@@ -197,7 +205,7 @@ Module.prototype.processState_tokenize = function (newUrl) {
197
205
  const storeResponse = await self.libraries.admin.firestore().doc(`users/${payload.user.auth.uid}`)
198
206
  .set({
199
207
  oauth2: {
200
- [payload.data.payload.service]: {
208
+ [payload.data.payload.provider]: {
201
209
  code: _.omit(
202
210
  _.merge({}, payload.data.payload),
203
211
  self.omittedPayloadFields,
@@ -238,7 +246,7 @@ Module.prototype.processState_deauthorize = function () {
238
246
  self.libraries.admin.firestore().doc(`users/${payload.user.auth.uid}`)
239
247
  .set({
240
248
  oauth2: {
241
- [payload.data.payload.service]: {},
249
+ [payload.data.payload.provider]: {},
242
250
  updated: {
243
251
  timestamp: assistant.meta.startTime.timestamp,
244
252
  timestampUNIX: assistant.meta.startTime.timestampUNIX,
@@ -256,7 +264,81 @@ Module.prototype.processState_deauthorize = function () {
256
264
  });
257
265
  };
258
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
+ }
259
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
+ };
260
342
 
261
343
 
262
344
  Module.prototype.processState_template = function (newUrl) {
@@ -271,11 +353,13 @@ Module.prototype.processState_template = function (newUrl) {
271
353
 
272
354
  return resolve({
273
355
  data: {
274
- authorizationUrl: finalUrl,
356
+ url: finalUrl,
275
357
  },
276
358
  redirect: payload.data.payload.redirect ? finalUrl : null
277
359
  });
278
360
  });
279
361
  };
280
362
 
363
+
364
+
281
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
  }