@sassoftware/viya-serverjs 0.5.1 → 0.5.2

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/src/iService.js CHANGED
@@ -27,15 +27,15 @@ let NodeCache = require("node-cache-promise");
27
27
  let Vision = require('@hapi/vision');
28
28
  let inert = require('@hapi/inert');
29
29
  let selfsigned = require('selfsigned');
30
- import { response } from '@hapi/inert/lib/file';
30
+
31
31
  import setupAuth from './plugins/setupAuth';
32
32
 
33
33
  let os = require('os');
34
34
 
35
- function iService (userRouteTable, useDefault, asset, allAppEnv, serverMode, userInfo) {
35
+ function iService(userRouteTable, useDefault, asset, allAppEnv, serverMode, userInfo) {
36
36
  // process.env.APPHOST_ADDR = process.env.APPHOST;
37
37
  const init = async () => {
38
-
38
+
39
39
  if (process.env.APPHOST === '*') {
40
40
  process.env.APPHOST = os.hostname();
41
41
  }
@@ -48,7 +48,7 @@ function iService (userRouteTable, useDefault, asset, allAppEnv, serverMode, use
48
48
  }
49
49
  let isSameSite = 'None';
50
50
  let isSecure = false;
51
-
51
+
52
52
  if (process.env.SAMESITE != null) {
53
53
  let [s1, s2] = process.env.SAMESITE.split(',');
54
54
  isSameSite = s1;
@@ -57,7 +57,7 @@ function iService (userRouteTable, useDefault, asset, allAppEnv, serverMode, use
57
57
  isSecure = false;
58
58
  }
59
59
  }
60
-
60
+
61
61
 
62
62
  let sConfig = {
63
63
  port: process.env.APPPORT,
@@ -65,19 +65,19 @@ function iService (userRouteTable, useDefault, asset, allAppEnv, serverMode, use
65
65
 
66
66
  state: {
67
67
  isSameSite: isSameSite,
68
- isSecure : isSecure,
68
+ isSecure: isSecure,
69
69
 
70
70
  },
71
-
71
+
72
72
 
73
73
  routes: {
74
74
  payload: {
75
75
  maxBytes: maxBytes
76
76
  },
77
77
  cors: {
78
- origin : ['*'],
78
+ origin: ['*'],
79
79
  credentials: true,
80
-
80
+
81
81
  "headers": ["Accept", "Authorization", "Content-Type", "If-None-Match", "Accept-language"]
82
82
  /*
83
83
  'Access-Control-Allow-Methods': ['GET', 'POST', 'OPTIONS'],
@@ -85,13 +85,13 @@ function iService (userRouteTable, useDefault, asset, allAppEnv, serverMode, use
85
85
  additionalExposedHeaders : ['location'],
86
86
  */
87
87
  }
88
-
88
+
89
89
  },
90
90
  };
91
91
  if (process.env.HAPIDEBUG === 'YES') {
92
92
  sConfig.debug = { request: '*' };
93
93
  }
94
- debug(JSON.stringify(sConfig, null,4));
94
+ debug(JSON.stringify(sConfig, null, 4));
95
95
  if (process.env.HTTPS === 'true') {
96
96
  sConfig.tls = await getCertificates();
97
97
  debug('Setup of SSL certificates completed');
@@ -99,7 +99,7 @@ function iService (userRouteTable, useDefault, asset, allAppEnv, serverMode, use
99
99
  debug('Running with no SSL certificates');
100
100
  }
101
101
  if (asset !== null) {
102
- sConfig.routes.files= { relativeTo: asset };
102
+ sConfig.routes.files = { relativeTo: asset };
103
103
  }
104
104
 
105
105
  debug2(
@@ -117,10 +117,10 @@ function iService (userRouteTable, useDefault, asset, allAppEnv, serverMode, use
117
117
  */
118
118
 
119
119
  let nodeCacheOptions = {
120
- stdTTL : 24*60*60*1000,
121
- checkPeriod : 3600,
120
+ stdTTL: 24 * 60 * 60 * 1000,
121
+ checkPeriod: 3600,
122
122
  errorOnMissing: true,
123
- useClones : false,
123
+ useClones: false,
124
124
  deleteOnExpire: true,
125
125
  };
126
126
  let storeCache = new NodeCache(nodeCacheOptions);
@@ -128,9 +128,9 @@ function iService (userRouteTable, useDefault, asset, allAppEnv, serverMode, use
128
128
 
129
129
  // common plugins
130
130
  let visionOptions = {
131
- engines : { html: require('handlebars') },
131
+ engines: { html: require('handlebars') },
132
132
  relativeTo: __dirname,
133
- path : '.',
133
+ path: '.',
134
134
  };
135
135
  await hapiServer.register(Vision);
136
136
  hapiServer.views(visionOptions);
@@ -140,7 +140,7 @@ function iService (userRouteTable, useDefault, asset, allAppEnv, serverMode, use
140
140
  }
141
141
  // register H202 for proxy handling
142
142
  // https://hapi.dev/module/h2o2/api/?v=10.0.1
143
-
143
+
144
144
  await hapiServer.register(H202);
145
145
  /*
146
146
  await hapiServer.register({
@@ -151,86 +151,87 @@ function iService (userRouteTable, useDefault, asset, allAppEnv, serverMode, use
151
151
  },
152
152
  });
153
153
  */
154
-
154
+
155
155
  //
156
156
  // setup authentication related plugins
157
-
157
+
158
158
  let options = {
159
- serverMode : serverMode,
160
- authFlow : process.env.AUTHFLOW,
161
- host : process.env.VIYA_SERVER,
162
- isSameSite : isSameSite,
163
- isSecure : isSecure,
164
- ns : (allAppEnv.LOGONPAYLOAD != null) ? allAppEnv.LOGONPAYLOAD.ns : null,
165
- nsHost : (allAppEnv.LOGONPAYLOAD != null) ? allAppEnv.LOGONPAYLOAD.nsHost : null,
166
- redirect : process.env.REDIRECT,
167
- clientId : process.env.CLIENTID,
168
- clientSecret : process.env.CLIENTSECRET,
169
- pkce : allAppEnv.LOGONPAYLOAD.pkce,
170
- redirectTo : `/${process.env.APPNAME}/logon`,
171
- allAppEnv : allAppEnv,
172
- useHapiCookie : true,
173
- appName : process.env.APPNAME,
174
- appHost : process.env.APPHOST,
175
- appPort : process.env.APPPORT,
159
+ serverMode: serverMode,
160
+ authFlow: process.env.AUTHFLOW,
161
+ host: process.env.VIYA_SERVER,
162
+ useLogon: (process.env.USELOGON != null && process.env.USELOGON.toUpperCase() === 'FALSE') ? false : true,
163
+ isSameSite: isSameSite,
164
+ isSecure: isSecure,
165
+ ns: (allAppEnv.LOGONPAYLOAD != null) ? allAppEnv.LOGONPAYLOAD.ns : null,
166
+ nsHost: (allAppEnv.LOGONPAYLOAD != null) ? allAppEnv.LOGONPAYLOAD.nsHost : null,
167
+ redirect: process.env.REDIRECT,
168
+ clientId: process.env.CLIENTID,
169
+ clientSecret: process.env.CLIENTSECRET,
170
+ pkce: allAppEnv.LOGONPAYLOAD.pkce,
171
+ redirectTo: `/${process.env.APPNAME}/logon`,
172
+ allAppEnv: allAppEnv,
173
+ useHapiCookie: true,
174
+ appName: process.env.APPNAME,
175
+ appHost: process.env.APPHOST,
176
+ appPort: process.env.APPPORT,
176
177
  userRouteTable: userRouteTable,
177
- useDefault : useDefault, /* not used - left here for potential reuse */
178
- userInfo : userInfo,
179
- https : process.env.HTTPS,
180
- authDefault : false, /* set later in setDefaultRoutes */
181
- authLogon : false /* set later in setDefaultRoutes */
178
+ useDefault: useDefault, /* not used - left here for potential reuse */
179
+ userInfo: userInfo,
180
+ https: process.env.HTTPS,
181
+ authDefault: false, /* set later in setDefaultRoutes */
182
+ authLogon: false /* set later in setDefaultRoutes */
182
183
 
183
184
  };
184
-
185
- debug2('Options',options);
185
+
186
+ debug2('Options', options);
186
187
  if (process.env.AUTHFLOW != null) {
187
- await setupAuth(hapiServer, options);
188
- if (process.env.PREAUTH === 'YES') {
188
+ await setupAuth(hapiServer, options);
189
+ if (process.env.PREAUTH === 'YES') {
189
190
  console.log('Preauth enabled');
190
191
  hapiServer.ext('onPreAuth', (request, h) => {
191
192
  debugger;
192
193
  if (!request.auth.isAuthenticated && !request.path.startsWith(`/login`)) {
193
- const redirectTo = `${request.path}?${new URLSearchParams(request.query).toString()}`;
194
- console.log('Redirect to login', {redirectTo});
195
- debugger;
196
- return h.redirect(`/login`).takeover();
194
+ const redirectTo = `${request.path}?${new URLSearchParams(request.query).toString()}`;
195
+ console.log('Redirect to login', { redirectTo });
196
+ debugger;
197
+ return h.redirect(`/login`).takeover();
197
198
  }
198
199
  return h.continue;
199
200
  });
200
201
  }
201
202
  }
202
203
  console.log('Plugin', process.env.PLUGIN);
203
-
204
- if (process.env.PLUGIN === 'hapi-swagger' && serverMode ==='api') {
205
- let swaggerOptions = {
204
+
205
+ if (process.env.PLUGIN === 'hapi-swagger' && serverMode === 'api') {
206
+ let swaggerOptions = {
206
207
  "info": {
207
- "title" : `API for ${process.env.APPNAME}`,
208
- "version" : "0.0.1",
208
+ "title": `API for ${process.env.APPNAME}`,
209
+ "version": "0.0.1",
209
210
  "description": "This document was auto-generated at run time"
210
211
  },
211
- "schemes" : ["http", "https"],
212
- "cors" : true,
213
- "debug" : true,
214
- "jsonPath" : `/${options.appName}/swagger.json`,
215
- "jsonRoutePath" : `/${options.appName}/swagger.json`,
216
- "documentationPage": true,
217
- "documentationPath": `/${options.appName}/documentation`,
218
- "swaggerUI" : true,
219
- "swaggerUIPath" : `/${options.appName}/swaggerui`,
220
- auth : options.authDefault
221
- };
212
+ "schemes": ["http", "https"],
213
+ "cors": true,
214
+ "debug": true,
215
+ "jsonPath": `/${options.appName}/swagger.json`,
216
+ "jsonRoutePath": `/${options.appName}/swagger.json`,
217
+ "documentationPage": true,
218
+ "documentationPath": `/${options.appName}/documentation`,
219
+ "swaggerUI": true,
220
+ "swaggerUIPath": `/${options.appName}/swaggerui`,
221
+ auth: options.authDefault
222
+ };
222
223
 
223
224
  if (userInfo != null) {
224
- let override = userInfo(options, 'SWAGGEROPTIONS');
225
- swaggerOptions = {...swaggerOptions, ...override};
225
+ let override = userInfo(options, 'SWAGGEROPTIONS');
226
+ swaggerOptions = { ...swaggerOptions, ...override };
226
227
  }
227
-
228
- debug('Swagger Options:' ,swaggerOptions);
228
+
229
+ debug('Swagger Options:', swaggerOptions);
229
230
  await hapiServer.register({ plugin: serverMode, options: swaggerOptions });
230
231
  } else if (process.env.PLUGIN == 'hapi-openapi' && serverMode === 'api') {
231
232
  console.log('hapi-openapi', 'coming soon');
232
- }
233
-
233
+ }
234
+
234
235
 
235
236
  //
236
237
  // Start server
@@ -246,7 +247,7 @@ function iService (userRouteTable, useDefault, asset, allAppEnv, serverMode, use
246
247
  options.serverMode === 'app'
247
248
  ? `Visit ${hh}/${process.env.APPNAME} to access application`
248
249
  : `Visit ${hh}/${process.env.APPNAME}/api to access swagger`;
249
- console.log('\x1b[1m%s\x1b[0m',msg);
250
+ console.log('\x1b[1m%s\x1b[0m', msg);
250
251
  console.log('NOTE: If running in container use the exported port');
251
252
  process.env.APPSERVER = `${hh}/${process.env.APPNAME}`;
252
253
  process.env.HEALTH = 'true';
@@ -260,100 +261,121 @@ function iService (userRouteTable, useDefault, asset, allAppEnv, serverMode, use
260
261
  init();
261
262
  }
262
263
 
263
- async function getCertificates () {
264
+ async function getCertificates() {
264
265
 
265
266
  let options = null;
266
267
  let tlsdir = process.env.SSLCERT;
267
- if (tlsdir != null && tlsdir.trim().length > 0) {
268
+ console.log('Reading SSL certificates from ', tlsdir);
269
+ if (tlsdir != null && tlsdir.trim().length > 0) {
268
270
  options = readTLS(tlsdir);
269
- options.rejectUnauthorized= true;
271
+ options.rejectUnauthorized = true;
270
272
  } else {
271
273
  console.log('No SSL certificates found, generating self-signed certificates');
272
274
  options = await getTls();
273
- options.rejectUnauthorized= false;
275
+ options.rejectUnauthorized = false;
274
276
  }
275
277
  return options;
276
278
  }
277
279
 
278
- function readTLS (tlsdir) {
279
- console.log("[Note] Using TLS dir: " + tlsdir);
280
- if (fs.existsSync(tlsdir) === false) {
281
- console.log("[Warning] Specified TLS dir does not exist: " + tlsdir);
282
- return null;
283
- }
284
-
285
- let listOfFiles = fs.readdirSync(tlsdir);
286
- console.log("[Note] TLS/SSL files found: " + listOfFiles);
287
- let options = {};
288
- for(let i=0; i < listOfFiles.length; i++) {
289
- let fname = listOfFiles[i];
290
- let name = tlsdir + '/' + listOfFiles[i];
291
- let key = fname.split('.')[0];
292
- options[key] = fs.readFileSync(name, { encoding: 'utf8' });
293
- }
294
- console.log('TLS FILES', Object.keys(options));
295
- return options;
296
-
280
+ function readTLS(tlsdir) {
281
+ console.log("[Note] Using TLS dir: " + tlsdir);
282
+ if (fs.existsSync(tlsdir) === false) {
283
+ console.log("[Warning] Specified TLS dir does not exist: " + tlsdir);
284
+ return null;
285
+ }
286
+
287
+ let listOfFiles = fs.readdirSync(tlsdir);
288
+ console.log("[Note] TLS/SSL files found: " + listOfFiles);
289
+ let options = {};
290
+ for (let i = 0; i < listOfFiles.length; i++) {
291
+ let fname = listOfFiles[i];
292
+ let name = tlsdir + '/' + listOfFiles[i];
293
+ let key = fname.split('.')[0];
294
+ options[key] = fs.readFileSync(name, { encoding: 'utf8' });
295
+ }
296
+ console.log('TLS FILES', Object.keys(options));
297
+ return options;
298
+
297
299
  }
298
300
 
299
- async function getTls () {
301
+ async function getTls() {
300
302
  let options = {
301
- keySize : 2048,
302
- days : 360,
303
- algorithm : "sha256",
303
+ keySize: 2048,
304
+ days: 360,
305
+ algorithm: "sha256",
304
306
  clientCertificate: true,
305
- extensions : {},
307
+ extensions: {},
306
308
  };
307
309
  let subjt = process.env.TLS_CREATE.replaceAll('"', '').trim();
308
- let subj = subjt.split(',');
309
-
310
+ let subj = subjt.split(',');
311
+
310
312
  let d = {};
311
313
  subj.map(c => {
312
314
  let r = c.split(':');
313
- d[ r[ 0 ] ] = r[ 1 ];
314
- return { value: r[ 1 ] };
315
+ d[r[0]] = r[1];
316
+ return { value: r[1] };
315
317
  });
316
318
 
317
319
  // TLS_CREATE=C:US,ST:NC,L:Cary,O:SAS Institute,OU:STO,CN:localhost,ALT:na.sas.com
318
320
  let attr = [
319
321
  {
320
- name : 'commonName',
322
+ name: 'commonName',
321
323
  value: d.CN /*process.env.APPHOST*/,
322
324
  },
323
325
  {
324
- name : 'countryName',
326
+ name: 'countryName',
325
327
  value: d.C
326
328
  }, {
327
329
  shortName: 'ST',
328
- value : d.ST
330
+ value: d.ST
329
331
  }, {
330
- name : 'localityName',
332
+ name: 'localityName',
331
333
  value: d.L,
332
334
  }, {
333
- name : 'organizationName',
335
+ name: 'organizationName',
334
336
  value: d.O
335
337
  },
336
338
  {
337
339
  shortName: 'OU',
338
- value : d.OU
340
+ value: d.OU
339
341
  }
340
342
  ];
343
+ /*
344
+ options.extensions.altNames = [
345
+ // { type: 6, value: `http://${process.env.APPHOST}:${process.env.APPPORT}/${process.env.APPNAME}` },
346
+ { type: 6, value: `https://${process.env.APPHOST}:${process.env.APPPORT}/${process.env.APPNAME}` },
347
+ { type: 6, value: `https://${process.env.APPHOST}:${process.env.APPPORT}/${process.env.APPNAME}/api` },
348
+ { type: 6, value: `https://${process.env.APPHOST}:${process.env.APPPORT}/${process.env.APPNAME}/logon` },
349
+ { type: 6, value: `https://${process.env.APPHOST}/${process.env.APPNAME}` },
350
+ { type: 6, value: `https://${process.env.APPHOST}/${process.env.APPNAME}/api` },
351
+ { type: 6, value: `https://${process.env.APPHOST}/${process.env.APPNAME}/logon` },
352
+ ];
353
+
354
+ options.extensions.altNames = [
355
+ { type: 2, value: 'localhost' }, // DNS
356
+ { type: 7, ip: '127.0.0.1' }, // IPv4
357
+ { type: 7, ip: '::1' } // IPv6
358
+ ];
359
+ */
360
+ options.extensions = [
361
+ {
362
+ name: 'subjectAltName',
363
+ altNames: [
364
+ { type: 2, value: 'localhost' }, // DNS
365
+ { type: 7, ip: '127.0.0.1' }, // IPv4
366
+ { type: 7, ip: '::1' } // IPv6
367
+
368
+ ]
369
+ }
341
370
 
342
- options.extensions.altNames = [
343
- // { type: 6, value: `http://${process.env.APPHOST}:${process.env.APPPORT}/${process.env.APPNAME}` },
344
- { type: 6, value: `https://${process.env.APPHOST}:${process.env.APPPORT}/${process.env.APPNAME}` },
345
- { type: 6, value: `https://${process.env.APPHOST}:${process.env.APPPORT}/${process.env.APPNAME}/api` },
346
- { type: 6, value: `https://${process.env.APPHOST}:${process.env.APPPORT}/${process.env.APPNAME}/logon` },
347
- { type: 6, value: `https://${process.env.APPHOST}/${process.env.APPNAME}` },
348
- { type: 6, value: `https://${process.env.APPHOST}/${process.env.APPNAME}/api` },
349
- { type: 6, value: `https://${process.env.APPHOST}/${process.env.APPNAME}/logon` },
350
371
  ];
351
- debug('tls options ', JSON.stringify(options, null,4));
372
+ console.log('tls options ', JSON.stringify(options, null, 4));
352
373
  let pems = selfsigned.generate(attr, options);
353
374
  let tls = {
354
375
  cert: pems.cert,
355
- key : pems.private
376
+ key: pems.private
356
377
  };
378
+ console.log('Self-signed certificates created', tls);
357
379
  return tls;
358
380
 
359
381
 
@@ -19,7 +19,7 @@
19
19
 
20
20
  async function setContext (req,h){
21
21
  let credentials = req.auth.credentials;
22
-
22
+ console.log('+++++++++++++++++++setContext', credentials != null);
23
23
  let context = {
24
24
  path : req.path,
25
25
  params : req.params,
@@ -29,6 +29,7 @@ async function setContext (req,h){
29
29
  token : (credentials != null) ? `bearer ${credentials.token}` : null,
30
30
  host : process.env.VIYA_SERVER
31
31
  };
32
+
32
33
  return context;
33
34
  }
34
35
  export default setContext;
@@ -73,15 +73,14 @@ module.exports = function setDefaultRoutes(server, options) {
73
73
  path: `${appName}/logon`,
74
74
  options: {
75
75
 
76
- auth: (options.authFlow === "server") ?
77
- { mode: "try", strategy: "sas" } : null,
76
+ auth: /*authLogon*/ (options.authFlow === "server") ? { mode: "try", strategy: "sas" } : null,
78
77
  //https://futurestud.io/tutorials/hapi-redirect-to-previous-page-after-login
79
78
  // set auth to null on all protected routes
80
79
  plugins: {
81
80
  "hapi-auth-cookie": { redirectTo: false },
82
81
  },
83
82
  handler: async (req, h) => {
84
- debug('logonhandler', req.auth.credentials);
83
+ console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>in logon');
85
84
  return await logon(req, h);
86
85
  }
87
86
  },
@@ -91,10 +90,14 @@ module.exports = function setDefaultRoutes(server, options) {
91
90
  path: `${appName}`,
92
91
 
93
92
  options: {
94
- auth: (process.env.USELOGON === 'YES') ? null : options.serverMode === "app" ? authLogon : authDefault,
95
- handler: getAppb,
96
- },
97
- },
93
+ //auth: (process.env.USELOGON.toUpperCase() === 'TRUE') ? null : options.serverMode === "app" ? authLogon : authDefault,
94
+ auth: null,
95
+ handler: async (req,h) => {
96
+ console.log(`>>>>>>>>>>>>>>>>>>>>>>>in ${appName}`);
97
+ return getAppb(req, h);
98
+ }
99
+ }
100
+ },
98
101
 
99
102
  {
100
103
  method: ["GET"],
@@ -254,6 +257,7 @@ module.exports = function setDefaultRoutes(server, options) {
254
257
  // now set pre for all default routes
255
258
  defaultTable.forEach((r) => {
256
259
  r.options.pre = [{method: setContext, assign: 'context'}];
260
+ console.log,('Setting pre for route', r.path,r.options.pre);
257
261
  });
258
262
  let routeTables =
259
263
  uTable !== null ? defaultTable.concat(uTable) : defaultTable;
package/testca.js ADDED
@@ -0,0 +1,10 @@
1
+ const https = require('https');
2
+ const url = 'https://localhost:8080/mcp'; // your mkcert HTTPS endpoint
3
+
4
+ https.get(url, { rejectUnauthorized: true }, (res) => {
5
+ console.log('✅ SUCCESS: mkcert rootCA is trusted by Node!');
6
+ console.log('Status:', res.statusCode);
7
+ }).on('error', (err) => {
8
+ console.error('❌ FAIL: mkcert rootCA NOT trusted');
9
+ console.error('Error:', err.message);
10
+ });