cloudcms-server 3.2.287 → 3.2.289

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/index.js CHANGED
@@ -48,6 +48,13 @@ if (process.env.DEFAULT_HTTP_TIMEOUT_MS)
48
48
  }
49
49
  }
50
50
 
51
+ // dns fix for Node 17 +
52
+ // see: https://nodejs.org/api/dns.html#dnssetdefaultresultorderorder
53
+ var dns = require("dns");
54
+ if (typeof(dns.setDefaultResultOrder) !== "undefined") {
55
+ dns.setDefaultResultOrder("ipv4first");
56
+ }
57
+
51
58
  // default agents
52
59
  var HttpKeepAliveAgent = require('agentkeepalive');
53
60
  var HttpsKeepAliveAgent = require('agentkeepalive').HttpsAgent;
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "author": {
3
3
  "name": "Gitana Software, Inc.",
4
- "email": "info@cloudcms.com",
5
- "url": "https://www.cloudcms.com"
4
+ "email": "info@gitana.io",
5
+ "url": "https://gitana.io"
6
6
  },
7
7
  "name": "cloudcms-server",
8
8
  "description": "Cloud CMS Application Server Module",
9
- "version": "3.2.287",
9
+ "version": "3.2.289",
10
10
  "repository": {
11
11
  "type": "git",
12
12
  "url": "git://github.com/gitana/cloudcms-server.git"
@@ -40,12 +40,12 @@
40
40
  "express-session": "^1.17.3",
41
41
  "express-useragent": "^1.0.15",
42
42
  "extend-with-super": "^2.0.0",
43
+ "fast-proxy": "^2.2.0",
43
44
  "finalhandler": "^1.2.0",
44
45
  "gitana": "^1.0.322",
45
46
  "handlebars": "^4.4.2",
46
47
  "hbs": "^4.0.5",
47
48
  "helmet": "^4.6.0",
48
- "http2-proxy": "^5.0.53",
49
49
  "ioredis": "4.28.5",
50
50
  "json5": "^1.0.1",
51
51
  "jsonwebtoken": "^8.5.1",
package/util/auth.js CHANGED
@@ -327,23 +327,29 @@ var syncProfile = exports.syncProfile = function(req, res, strategy, domainId, p
327
327
  }
328
328
 
329
329
  _LOCK([CACHE_IDENTIFIER], function(err, releaseLockFn) {
330
+
331
+ if (err) {
332
+ try { releaseLockFn(); } catch (e) { }
333
+ return callback(err);
334
+ }
335
+
330
336
  _handleSyncUser(req, strategy, settings, key, domainId, providerId, providerUserId, token, refreshToken, userObject, groupsArray, function (err, gitanaUser) {
331
337
 
332
338
  if (err) {
333
- releaseLockFn();
339
+ try { releaseLockFn(); } catch (e) { }
334
340
  return callback(err);
335
341
  }
336
342
 
337
343
  // no user found
338
344
  if (!gitanaUser) {
339
- releaseLockFn();
345
+ try { releaseLockFn(); } catch (e) { }
340
346
  return callback();
341
347
  }
342
348
 
343
349
  _handleConnectAsUser(req, key, gitanaUser, function (err, platform, appHelper, key) {
344
350
 
345
351
  if (err) {
346
- releaseLockFn();
352
+ try { releaseLockFn(); } catch (e) { }
347
353
  return callback(err);
348
354
  }
349
355
 
@@ -354,8 +360,8 @@ var syncProfile = exports.syncProfile = function(req, res, strategy, domainId, p
354
360
  "appHelper": appHelper,
355
361
  "key": key
356
362
  });
357
-
358
- releaseLockFn();
363
+
364
+ try { releaseLockFn(); } catch (e) { }
359
365
 
360
366
  callback(err, gitanaUser, platform, appHelper, key, platform.getDriver());
361
367
  }, gitanaUser);
@@ -0,0 +1,281 @@
1
+ var http = require("http");
2
+ var https = require("https");
3
+ var path = require("path");
4
+
5
+ var auth = require("./auth");
6
+ var util = require("./util");
7
+
8
+ var oauth2 = require("./oauth2")();
9
+
10
+ var urlTool = require("url");
11
+ const finalhandler = require("finalhandler");
12
+
13
+ var LRU = require("lru-cache");
14
+
15
+ var exports = module.exports;
16
+
17
+ var _LOCK = function(lockIdentifiers, workFunction)
18
+ {
19
+ var name = lockIdentifiers.join("_");
20
+ process.locks.lock(name, workFunction);
21
+ };
22
+
23
+ var NAMED_PROXY_HANDLERS_CACHE = new LRU({
24
+ max: 200,
25
+ ttl: 1000 * 60 * 60 // 60 minutes
26
+ });
27
+
28
+ var acquireProxyHandler = exports.acquireProxyHandler = function(proxyTarget, pathPrefix, callback)
29
+ {
30
+ var name = path.join(proxyTarget, (pathPrefix || "/"));
31
+
32
+ // is it already in LRU cache?
33
+ // if so hand it back
34
+ var _cachedHandler = NAMED_PROXY_HANDLERS_CACHE[name];
35
+ if (_cachedHandler)
36
+ {
37
+ return callback(null, _cachedHandler);
38
+ }
39
+
40
+ // take out a thread lock
41
+ _LOCK(["acquireProxyHandler", name], function(err, releaseLockFn) {
42
+
43
+ if (err)
44
+ {
45
+ console.log("Failed to acquire proxy handler: " + name + ", err: ", err);
46
+
47
+ // failed to acquire lock
48
+ return callback(err);
49
+ }
50
+
51
+ // second check to make sure another thread didn't create the handler in the meantime
52
+ _cachedHandler = NAMED_PROXY_HANDLERS_CACHE[name];
53
+ if (_cachedHandler)
54
+ {
55
+ releaseLockFn();
56
+ return callback(null, _cachedHandler);
57
+ }
58
+
59
+ // create the proxy handler and cache it into LRU cache
60
+ //console.log("Acquiring proxy handler: " + name + ", for target: " + proxyTarget + " and prefix: " + pathPrefix);
61
+ _cachedHandler = createProxyHandler(proxyTarget, pathPrefix);
62
+
63
+ // store back into LRU cache
64
+ NAMED_PROXY_HANDLERS_CACHE[name] = _cachedHandler;
65
+
66
+ releaseLockFn();
67
+ callback(null, _cachedHandler);
68
+ });
69
+ };
70
+
71
+
72
+
73
+
74
+ var createProxyHandler = function(proxyTarget, pathPrefix)
75
+ {
76
+ const proxy = require("http2-proxy");
77
+ const finalhandler = require('finalhandler')
78
+
79
+ const defaultWebHandler = function(err, req, res) {
80
+ if (err)
81
+ {
82
+ console.log("A web proxy error was caught, path: " + req.path + ", err: ", err);
83
+ try { res.status(500); } catch (e) { }
84
+ try { res.end('Something went wrong while proxying the request.'); } catch (e) { }
85
+ }
86
+
87
+ finalhandler(req, res)(err);
88
+ };
89
+
90
+ // const defaultWsHandler = function(err, req, socket, head) {
91
+ // if (err) {
92
+ // console.error('proxy error (ws)', err);
93
+ // socket.destroy();
94
+ // }
95
+ // };
96
+
97
+ //console.log("Proxy Target: " + proxyTarget);
98
+
99
+ var hostname = urlTool.parse(proxyTarget).hostname;
100
+ var port = urlTool.parse(proxyTarget).port;
101
+ var protocol = urlTool.parse(proxyTarget).protocol;
102
+
103
+ // web
104
+ var webConfig = {};
105
+ webConfig.hostname = hostname;
106
+ webConfig.port = port;
107
+ webConfig.protocol = protocol;
108
+ //webConfig.path = null;
109
+ webConfig.timeout = 120000;
110
+ webConfig.proxyTimeout = 120000;
111
+ webConfig.proxyName = "Cloud CMS UI Proxy";
112
+ webConfig.onReq = function(req, options) {
113
+
114
+ if (!options.headers) {
115
+ options.headers = {};
116
+ }
117
+ var headers = options.headers;
118
+
119
+ if (options.path && options.path.startsWith("/proxy")) {
120
+ options.path = options.path.substring(6);
121
+ }
122
+
123
+ if (pathPrefix) {
124
+ options.path = path.join(pathPrefix, options.path);
125
+ }
126
+
127
+ // used to auto-assign the client header for /oauth/token requests
128
+ oauth2.autoProxy(req);
129
+
130
+ // copy domain host into "x-cloudcms-domainhost"
131
+ if (req.domainHost) {
132
+ headers["x-cloudcms-domainhost"] = req.domainHost; // this could be "localhost"
133
+ }
134
+
135
+ // copy virtual host into "x-cloudcms-virtualhost"
136
+ if (req.virtualHost) {
137
+ headers["x-cloudcms-virtualhost"] = req.virtualHost; // this could be "root.cloudcms.net" or "abc.cloudcms.net"
138
+ }
139
+
140
+ // copy deployment descriptor info
141
+ if (req.descriptor)
142
+ {
143
+ if (req.descriptor.tenant)
144
+ {
145
+ if (req.descriptor.tenant.id)
146
+ {
147
+ headers["x-cloudcms-tenant-id"] = req.descriptor.tenant.id;
148
+ }
149
+
150
+ if (req.descriptor.tenant.title)
151
+ {
152
+ headers["x-cloudcms-tenant-title"] = req.descriptor.tenant.title;
153
+ }
154
+ }
155
+
156
+ if (req.descriptor.application)
157
+ {
158
+ if (req.descriptor.application.id)
159
+ {
160
+ headers["x-cloudcms-application-id"] = req.descriptor.application.id;
161
+ }
162
+
163
+ if (req.descriptor.application.title)
164
+ {
165
+ headers["x-cloudcms-application-title"] = req.descriptor.application.title;
166
+ }
167
+ }
168
+ }
169
+
170
+ // set optional "x-cloudcms-origin" header
171
+ var cloudcmsOrigin = null;
172
+ if (req.virtualHost)
173
+ {
174
+ cloudcmsOrigin = req.virtualHost;
175
+ }
176
+ if (cloudcmsOrigin)
177
+ {
178
+ headers["x-cloudcms-origin"] = cloudcmsOrigin;
179
+ }
180
+
181
+ // set x-cloudcms-server-version header
182
+ headers["x-cloudcms-server-version"] = process.env.CLOUDCMS_APPSERVER_PACKAGE_VERSION;
183
+
184
+ // keep alive
185
+ //req.headers["connection"] = "keep-alive";
186
+
187
+ // if the incoming request didn't have an "Authorization" header
188
+ // and we have a logged in Gitana User via Auth, then set authorization header to Bearer Access Token
189
+ if (!req.headers["authorization"])
190
+ {
191
+ if (req.gitana_user)
192
+ {
193
+ headers["authorization"] = "Bearer " + req.gitana_user.getDriver().http.accessToken();
194
+ }
195
+ else if (req.gitana_proxy_access_token)
196
+ {
197
+ headers["authorization"] = "Bearer " + req.gitana_proxy_access_token;
198
+ }
199
+ }
200
+ };
201
+ webConfig.onRes = function(req, res, proxyRes) {
202
+
203
+ if (req.gitana_user)
204
+ {
205
+ var chunks = [];
206
+
207
+ // triggers on data receive
208
+ proxyRes.on('data', function(chunk) {
209
+ // add received chunk to chunks array
210
+ chunks.push(chunk);
211
+ });
212
+
213
+ proxyRes.on("end", function () {
214
+
215
+ if (proxyRes.statusCode === 401)
216
+ {
217
+ var text = "" + Buffer.concat(chunks);
218
+ if (text && (text.indexOf("invalid_token") > -1) || (text.indexOf("invalid_grant") > -1))
219
+ {
220
+ var identifier = req.identity_properties.provider_id + "/" + req.identity_properties.user_identifier;
221
+
222
+ _LOCK([identifier], function(err, releaseLockFn) {
223
+
224
+ if (err)
225
+ {
226
+ // failed to acquire lock
227
+ console.log("FAILED TO ACQUIRE LOCK", err);
228
+ req.log("FAILED TO ACQUIRE LOCK", err);
229
+ try { releaseLockFn(); } catch (e) { }
230
+ return;
231
+ }
232
+
233
+ var cleanup = function (full)
234
+ {
235
+ delete Gitana.APPS[req.identity_properties.token];
236
+ delete Gitana.PLATFORM_CACHE[req.identity_properties.token];
237
+
238
+ if (full) {
239
+ auth.removeUserCacheEntry(identifier);
240
+ }
241
+ };
242
+
243
+ // null out the access token
244
+ // this will force the refresh token to be used to get a new one on the next request
245
+ req.gitana_user.getDriver().http.refresh(function (err) {
246
+
247
+ if (err) {
248
+ cleanup(true);
249
+ req.log("Invalidated auth state for gitana user: " + req.identity_properties.token);
250
+ return releaseLockFn();
251
+ }
252
+
253
+ req.gitana_user.getDriver().reloadAuthInfo(function () {
254
+ cleanup(true);
255
+ req.log("Refreshed token for gitana user: " + req.identity_properties.token);
256
+ releaseLockFn();
257
+ });
258
+ });
259
+ });
260
+ }
261
+
262
+ }
263
+ });
264
+ }
265
+
266
+ //res.setHeader('x-powered-by', 'cloudcms');
267
+ res.writeHead(proxyRes.statusCode, proxyRes.headers)
268
+ proxyRes.pipe(res)
269
+ };
270
+
271
+ var proxyRequestHandler = function(req, res) {
272
+ proxy.web(req, res, webConfig, function(err, req, res) {
273
+ defaultWebHandler(err, req, res);
274
+ });
275
+ };
276
+
277
+ // cookie domain rewrite?
278
+ // not needed - this is handled intrinsically by http2-proxy
279
+
280
+ return proxyRequestHandler;
281
+ };
@@ -1,15 +1,12 @@
1
- var http = require("http");
2
- var https = require("https");
1
+ // var http = require("http");
2
+ // var https = require("https");
3
3
  var path = require("path");
4
4
 
5
5
  var auth = require("./auth");
6
- var util = require("./util");
6
+ // var util = require("./util");
7
7
 
8
8
  var oauth2 = require("./oauth2")();
9
9
 
10
- var urlTool = require("url");
11
- const finalhandler = require("finalhandler");
12
-
13
10
  var LRU = require("lru-cache");
14
11
 
15
12
  var exports = module.exports;
@@ -73,59 +70,95 @@ var acquireProxyHandler = exports.acquireProxyHandler = function(proxyTarget, pa
73
70
 
74
71
  var createProxyHandler = function(proxyTarget, pathPrefix)
75
72
  {
76
- const proxy = require("http2-proxy");
77
- const finalhandler = require('finalhandler')
73
+ const { proxy, close } = require('fast-proxy')({
74
+ base: proxyTarget,
75
+ cacheURLs: 0,
76
+ http2: true,
77
+ //undici: true
78
+ });
78
79
 
79
- const defaultWebHandler = function(err, req, res) {
80
- if (err)
80
+ var proxyOptions = {};
81
+ proxyOptions.onResponse = function(req, res, stream) {
82
+
83
+ if (req.gitana_user)
81
84
  {
82
- console.log("A web proxy error was caught, path: " + req.path + ", err: ", err);
83
- try { res.status(500); } catch (e) { }
84
- try { res.end('Something went wrong while proxying the request.'); } catch (e) { }
85
- }
86
-
87
- finalhandler(req, res)(err);
88
- };
89
-
90
- // const defaultWsHandler = function(err, req, socket, head) {
91
- // if (err) {
92
- // console.error('proxy error (ws)', err);
93
- // socket.destroy();
94
- // }
95
- // };
96
-
97
- //console.log("Proxy Target: " + proxyTarget);
98
-
99
- var hostname = urlTool.parse(proxyTarget).hostname;
100
- var port = urlTool.parse(proxyTarget).port;
101
- var protocol = urlTool.parse(proxyTarget).protocol;
85
+ var chunks = [];
86
+
87
+ // triggers on data receive
88
+ stream.on('data', function(chunk) {
89
+ console.log("DATA!");
90
+ // add received chunk to chunks array
91
+ chunks.push(chunk);
92
+ });
102
93
 
103
- // web
104
- var webConfig = {};
105
- webConfig.hostname = hostname;
106
- webConfig.port = port;
107
- webConfig.protocol = protocol;
108
- //webConfig.path = null;
109
- webConfig.timeout = 120000;
110
- webConfig.proxyTimeout = 120000;
111
- webConfig.proxyName = "Cloud CMS UI Proxy";
112
- webConfig.onReq = function(req, options) {
113
-
114
- if (!options.headers) {
115
- options.headers = {};
116
- }
117
- var headers = options.headers;
118
-
119
- if (options.path && options.path.startsWith("/proxy")) {
120
- options.path = options.path.substring(6);
94
+ stream.on("end", function () {
95
+
96
+ if (stream.statusCode === 401)
97
+ {
98
+ var text = "" + Buffer.concat(chunks);
99
+ if (text && (text.indexOf("invalid_token") > -1) || (text.indexOf("invalid_grant") > -1))
100
+ {
101
+ var identifier = req.identity_properties.provider_id + "/" + req.identity_properties.user_identifier;
102
+
103
+ _LOCK([identifier], function(err, releaseLockFn) {
104
+
105
+ if (err)
106
+ {
107
+ // failed to acquire lock
108
+ console.log("FAILED TO ACQUIRE LOCK", err);
109
+ req.log("FAILED TO ACQUIRE LOCK", err);
110
+ try { releaseLockFn(); } catch (e) { }
111
+ return;
112
+ }
113
+
114
+ var cleanup = function (full)
115
+ {
116
+ delete Gitana.APPS[req.identity_properties.token];
117
+ delete Gitana.PLATFORM_CACHE[req.identity_properties.token];
118
+
119
+ if (full) {
120
+ auth.removeUserCacheEntry(identifier);
121
+ }
122
+ };
123
+
124
+ // null out the access token
125
+ // this will force the refresh token to be used to get a new one on the next request
126
+ req.gitana_user.getDriver().http.refresh(function (err) {
127
+
128
+ if (err) {
129
+ cleanup(true);
130
+ req.log("Invalidated auth state for gitana user: " + req.identity_properties.token);
131
+ return releaseLockFn();
132
+ }
133
+
134
+ req.gitana_user.getDriver().reloadAuthInfo(function () {
135
+ cleanup(true);
136
+ req.log("Refreshed token for gitana user: " + req.identity_properties.token);
137
+ releaseLockFn();
138
+ });
139
+ });
140
+ });
141
+ }
142
+
143
+ }
144
+ });
121
145
  }
122
146
 
123
- if (pathPrefix) {
124
- options.path = path.join(pathPrefix, options.path);
147
+ //res.setHeader('x-powered-by', 'cloudcms');
148
+ if (stream.statusCode && stream.headers) {
149
+ res.writeHead(stream.statusCode, stream.headers)
125
150
  }
126
151
 
152
+ stream.pipe(res)
153
+ };
154
+ proxyOptions.rewriteRequestHeaders = function(req, headers)
155
+ {
127
156
  // used to auto-assign the client header for /oauth/token requests
128
157
  oauth2.autoProxy(req);
158
+ if (req.headers && req.headers.authorization)
159
+ {
160
+ headers["authorization"] = req.headers.authorization;
161
+ }
129
162
 
130
163
  // copy domain host into "x-cloudcms-domainhost"
131
164
  if (req.domainHost) {
@@ -197,85 +230,21 @@ var createProxyHandler = function(proxyTarget, pathPrefix)
197
230
  headers["authorization"] = "Bearer " + req.gitana_proxy_access_token;
198
231
  }
199
232
  }
200
- };
201
- webConfig.onRes = function(req, res, proxyRes) {
202
-
203
- if (req.gitana_user)
204
- {
205
- var chunks = [];
206
-
207
- // triggers on data receive
208
- proxyRes.on('data', function(chunk) {
209
- // add received chunk to chunks array
210
- chunks.push(chunk);
211
- });
212
-
213
- proxyRes.on("end", function () {
214
-
215
- if (proxyRes.statusCode === 401)
216
- {
217
- var text = "" + Buffer.concat(chunks);
218
- if (text && (text.indexOf("invalid_token") > -1) || (text.indexOf("invalid_grant") > -1))
219
- {
220
- var identifier = req.identity_properties.provider_id + "/" + req.identity_properties.user_identifier;
221
-
222
- _LOCK([identifier], function(err, releaseLockFn) {
223
-
224
- if (err)
225
- {
226
- // failed to acquire lock
227
- console.log("FAILED TO ACQUIRE LOCK", err);
228
- req.log("FAILED TO ACQUIRE LOCK", err);
229
- try { releaseLockFn(); } catch (e) { }
230
- return;
231
- }
232
-
233
- var cleanup = function (full)
234
- {
235
- delete Gitana.APPS[req.identity_properties.token];
236
- delete Gitana.PLATFORM_CACHE[req.identity_properties.token];
237
-
238
- if (full) {
239
- auth.removeUserCacheEntry(identifier);
240
- }
241
- };
242
-
243
- // null out the access token
244
- // this will force the refresh token to be used to get a new one on the next request
245
- req.gitana_user.getDriver().http.refresh(function (err) {
246
-
247
- if (err) {
248
- cleanup(true);
249
- req.log("Invalidated auth state for gitana user: " + req.identity_properties.token);
250
- return releaseLockFn();
251
- }
252
-
253
- req.gitana_user.getDriver().reloadAuthInfo(function () {
254
- cleanup(true);
255
- req.log("Refreshed token for gitana user: " + req.identity_properties.token);
256
- releaseLockFn();
257
- });
258
- });
259
- });
260
- }
261
-
262
- }
263
- });
264
- }
265
233
 
266
- //res.setHeader('x-powered-by', 'cloudcms');
267
- res.writeHead(proxyRes.statusCode, proxyRes.headers)
268
- proxyRes.pipe(res)
234
+ return headers;
235
+ };
236
+ // rewrite response headers
237
+ proxyOptions.rewriteHeaders = function(headers)
238
+ {
239
+ return headers;
269
240
  };
270
241
 
242
+ //////////////////////////////////////////////////////////////////////////
243
+
271
244
  var proxyRequestHandler = function(req, res) {
272
- proxy.web(req, res, webConfig, function(err, req, res) {
273
- defaultWebHandler(err, req, res);
274
- });
245
+
246
+ proxy(req, res, pathPrefix, proxyOptions);
275
247
  };
276
248
 
277
- // cookie domain rewrite?
278
- // not needed - this is handled intrinsically by http2-proxy
279
-
280
249
  return proxyRequestHandler;
281
250
  };