@naanlang/naan 1.0.0 → 1.0.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/LICENSE.md +1 -1
- package/README.md +37 -8
- package/bin/index.js +148 -0
- package/dist/env_web.js +145 -16
- package/dist/naan.min.js +5 -5
- package/frameworks/browser/sworker.js +309 -91
- package/frameworks/browser/terminals.nlg +22 -9
- package/frameworks/browser/workers.nlg +19 -11
- package/frameworks/client/apiclient.nlg +17 -4
- package/frameworks/client/psm_client.nlg +116 -53
- package/frameworks/common/common.nlg +12 -2
- package/frameworks/node/apiserver.nlg +25 -13
- package/frameworks/node/filesystem.nlg +173 -30
- package/frameworks/node/psm_server.nlg +95 -32
- package/frameworks/project/build.nlg +40 -23
- package/frameworks/project/projects.nlg +47 -26
- package/frameworks/running/debugnub.nlg +2 -5
- package/frameworks/storage/csv.nlg +120 -0
- package/frameworks/storage/dbt_pouch.nlg +41 -25
- package/frameworks/storage/psm.nlg +108 -28
- package/frameworks/storage/psm_dbtables.nlg +7 -3
- package/frameworks/storage/resources.nlg +30 -2
- package/lib/browser/env_web.js +147 -18
- package/lib/browser/env_webworker.js +1 -1
- package/lib/browser/require.js +1 -1
- package/lib/core/naanlib.js +5 -5
- package/lib/env_node.js +14 -2
- package/lib/node_repl.js +2 -2
- package/package.json +4 -1
- package/plugins/serviceAws/aws_cloudwatchlogs.nlg +1 -1
- package/plugins/serviceAws/aws_dynamo.nlg +625 -141
- package/plugins/serviceAws/aws_dynextra.nlg +294 -0
- package/plugins/serviceAws/dbt_aws.nlg +31 -11
- package/plugins/serviceAws/psm_aws.nlg +42 -26
- package/plugins/serviceAws/serviceAws.nlg +1 -0
- package/plugins/serviceGitHub/psm_github.nlg +41 -25
- package/plugins/serviceGitLab/psm_gitlab.nlg +41 -25
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* column positioning: // // !
|
|
8
8
|
*
|
|
9
|
-
* Copyright (c) 2017-
|
|
9
|
+
* Copyright (c) 2017-2022 by Richard C. Zulch
|
|
10
10
|
*
|
|
11
11
|
*/
|
|
12
12
|
|
|
@@ -20,9 +20,10 @@
|
|
|
20
20
|
*
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
closure MakeNideAPIclient(url, local client) {
|
|
23
|
+
closure MakeNideAPIclient(url, guid, local client) {
|
|
24
24
|
client = new(object, this)
|
|
25
25
|
client.url = url
|
|
26
|
+
client.guid = guid
|
|
26
27
|
client.notifyAfter = 0
|
|
27
28
|
|
|
28
29
|
// clientRequest() - general request routine
|
|
@@ -51,6 +52,8 @@ closure MakeNideAPIclient(url, local client) {
|
|
|
51
52
|
request.responseType = options.responseType
|
|
52
53
|
if options.contentType
|
|
53
54
|
request.setRequestHeader("Content-Type", options.contentType)
|
|
55
|
+
if guid
|
|
56
|
+
request.setRequestHeader("x-naanlang-api-guid", guid)
|
|
54
57
|
request.send(options.putdata)
|
|
55
58
|
}
|
|
56
59
|
|
|
@@ -117,7 +120,7 @@ closure MakeNideAPIclient(url, local client) {
|
|
|
117
120
|
// Otherwise if communication failed then the result is:
|
|
118
121
|
// callback(<error>).
|
|
119
122
|
|
|
120
|
-
client.psmRemote = closure psmRemote(options, data, callback, local query, method, reqOptions) {
|
|
123
|
+
client.psmRemote = closure psmRemote(options, data, callback, local query, method, reqOptions, error) {
|
|
121
124
|
query = EncodeQuery("/psm/?", options)
|
|
122
125
|
if data
|
|
123
126
|
method = "PUT"
|
|
@@ -131,6 +134,16 @@ closure MakeNideAPIclient(url, local client) {
|
|
|
131
134
|
reqOptions.contentType = "application/octet-stream" // we are sending binary data
|
|
132
135
|
else
|
|
133
136
|
reqOptions.responseType = "arraybuffer" // we are requesting binary data
|
|
137
|
+
} else if options.encoding == "json" {
|
|
138
|
+
if data {
|
|
139
|
+
reqOptions.contentType = "application/json;charset=UTF-8" // we are sending JSON
|
|
140
|
+
`(error, data) = JsonStringify(data)
|
|
141
|
+
if error
|
|
142
|
+
return (callback(Error("psmRemote failed:", error)))
|
|
143
|
+
reqOptions.putdata = data
|
|
144
|
+
}
|
|
145
|
+
else
|
|
146
|
+
reqOptions.responseType = "application/json" // we are requesting JSON
|
|
134
147
|
}
|
|
135
148
|
clientRequest(method, url.concat(query), reqOptions, function (error, req, event, local data) {
|
|
136
149
|
if !error && req.status != 200
|
|
@@ -172,7 +185,7 @@ closure MakeNideAPIclient(url, local client) {
|
|
|
172
185
|
|
|
173
186
|
function apicInit(local manifest) {
|
|
174
187
|
|
|
175
|
-
manifest = `(
|
|
188
|
+
manifest = `(MakeNideAPIclient, apicInit)
|
|
176
189
|
|
|
177
190
|
Naan.module.build(module.id, "apiclient", function(modobj, compobj) {
|
|
178
191
|
Naan.module.require("./client.nlg")
|
|
@@ -123,7 +123,28 @@ closure psmcFsView(api, rootpath, local view, pathmod) {
|
|
|
123
123
|
view.writeFile = function writeFile(path, data, options, callback) {
|
|
124
124
|
psmRemote(path, "writeFile", options, data, callback)
|
|
125
125
|
}
|
|
126
|
-
|
|
126
|
+
|
|
127
|
+
// readlink
|
|
128
|
+
//
|
|
129
|
+
// Read the contents of a symbolic link at the specified path
|
|
130
|
+
|
|
131
|
+
view.readlink = function readlink(path, callback) {
|
|
132
|
+
psmRemote(path, "readlink", { }, false, callback)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// symlink
|
|
136
|
+
//
|
|
137
|
+
// Create a symbolic link path pointing to (containing the string) target
|
|
138
|
+
|
|
139
|
+
view.symlink = function symlink(target, path, options, callback) {
|
|
140
|
+
if options
|
|
141
|
+
options = new(options)
|
|
142
|
+
else
|
|
143
|
+
options = { }
|
|
144
|
+
options.target = target
|
|
145
|
+
psmRemote(path, "symlink", options, false, callback)
|
|
146
|
+
}
|
|
147
|
+
|
|
127
148
|
// delete
|
|
128
149
|
//
|
|
129
150
|
// Delete a file or directory at the specified path
|
|
@@ -134,12 +155,45 @@ closure psmcFsView(api, rootpath, local view, pathmod) {
|
|
|
134
155
|
|
|
135
156
|
// info
|
|
136
157
|
//
|
|
137
|
-
// Get file info at the specified path
|
|
158
|
+
// Get file or directory info at the specified path
|
|
159
|
+
|
|
160
|
+
view.info = function info(path, options, callback) {
|
|
161
|
+
if !options
|
|
162
|
+
options = { }
|
|
163
|
+
psmRemote(path, "info", options, false, callback)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// setInfo
|
|
167
|
+
//
|
|
168
|
+
// Set file or directory info obtained from info() call.
|
|
169
|
+
|
|
170
|
+
view.setInfo = function setInfo(path, info, callback) {
|
|
171
|
+
psmRemote(path, "setInfo", {
|
|
172
|
+
encoding: "json"
|
|
173
|
+
}, info, callback)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// setOwnerGroup
|
|
177
|
+
//
|
|
178
|
+
// Set file or directory owner or group at the specified path
|
|
138
179
|
|
|
139
|
-
view.
|
|
140
|
-
psmRemote(path, "
|
|
180
|
+
view.setOwnerGroup = function setOwnerGroup(path, uid, gid, callback) {
|
|
181
|
+
psmRemote(path, "setOwnerGroup", {
|
|
182
|
+
uid: uid
|
|
183
|
+
gid: gid
|
|
184
|
+
}, false, callback)
|
|
141
185
|
}
|
|
142
186
|
|
|
187
|
+
// setMode
|
|
188
|
+
//
|
|
189
|
+
// Set file or directory mode at the specified path
|
|
190
|
+
|
|
191
|
+
view.setMode = function setMode(path, mode, callback) {
|
|
192
|
+
psmRemote(path, "setMode", {
|
|
193
|
+
mode: mode
|
|
194
|
+
}, false, callback)
|
|
195
|
+
}
|
|
196
|
+
|
|
143
197
|
// setTimes
|
|
144
198
|
//
|
|
145
199
|
// Set file modify and access times at the specified path
|
|
@@ -157,7 +211,7 @@ closure psmcFsView(api, rootpath, local view, pathmod) {
|
|
|
157
211
|
|
|
158
212
|
view.dirList = function dirList(path, options, callback) {
|
|
159
213
|
psmRemote(path, "dirList", {
|
|
160
|
-
|
|
214
|
+
stat: options.stat
|
|
161
215
|
}, false, callback)
|
|
162
216
|
}
|
|
163
217
|
|
|
@@ -167,7 +221,7 @@ closure psmcFsView(api, rootpath, local view, pathmod) {
|
|
|
167
221
|
|
|
168
222
|
view.readir = function readir(path, callback) {
|
|
169
223
|
psmRemote(path, "dirList", {
|
|
170
|
-
|
|
224
|
+
stat: true
|
|
171
225
|
}, false, callback)
|
|
172
226
|
}
|
|
173
227
|
|
|
@@ -209,7 +263,9 @@ closure psmcFsView(api, rootpath, local view, pathmod) {
|
|
|
209
263
|
// delete the source after the copy.
|
|
210
264
|
|
|
211
265
|
view.copy = closure copy(srcpath, dest, options, callback, local parameters) {
|
|
212
|
-
if
|
|
266
|
+
if options
|
|
267
|
+
options = new(options)
|
|
268
|
+
else
|
|
213
269
|
options = { }
|
|
214
270
|
options.destination = JSpath.resolve(rootpath, dest)
|
|
215
271
|
psmRemote(srcpath, "copy", options, false, callback)
|
|
@@ -325,7 +381,7 @@ closure psmcFsConnector(psm, nicc, local connClassID, connector, watch) {
|
|
|
325
381
|
connector.psm = psm
|
|
326
382
|
connector.api = nicc.api
|
|
327
383
|
connector.vault = psm.vault(connClassID)
|
|
328
|
-
connector.label = "Naan
|
|
384
|
+
connector.label = "Naan-Server"
|
|
329
385
|
watch = psm.watchable(connector)
|
|
330
386
|
|
|
331
387
|
// uifields
|
|
@@ -337,57 +393,44 @@ closure psmcFsConnector(psm, nicc, local connClassID, connector, watch) {
|
|
|
337
393
|
placeholder: "http://host.com/endpoint"
|
|
338
394
|
key: "urlName" },
|
|
339
395
|
{
|
|
340
|
-
label: "Auth
|
|
341
|
-
placeholder: "
|
|
342
|
-
key: "
|
|
343
|
-
{
|
|
344
|
-
label: "Auth Password"
|
|
345
|
-
placeholder: "account password"
|
|
346
|
-
key: "authPW"
|
|
347
|
-
type: "password" },
|
|
396
|
+
label: "Auth Secret"
|
|
397
|
+
placeholder: "guid"
|
|
398
|
+
key: "authSecret" }
|
|
348
399
|
]
|
|
349
400
|
}
|
|
350
|
-
|
|
351
|
-
// hashResourceID
|
|
352
|
-
//
|
|
353
|
-
// Make a stable hash based on the resource credentials that we can persist or share between
|
|
354
|
-
// different domains accessing the same resource.
|
|
355
|
-
connector.hashResourceID = function hashResourceID(resource, local ident) {
|
|
356
|
-
ident = resource.urlName
|
|
357
|
-
if resource.label
|
|
358
|
-
ident = ident.concat(resource.label)
|
|
359
|
-
HashSHA256(ident)
|
|
360
|
-
}
|
|
361
401
|
|
|
362
402
|
// findResource
|
|
363
403
|
//
|
|
364
|
-
// Find a resource with the specified contents, returning the resID or false.
|
|
365
|
-
// is: if added, would the specified contents be redundant to an existing resource?
|
|
404
|
+
// Find a resource with the specified contents, returning the resID or false.
|
|
366
405
|
connector.findResource = function findResource(resource, local resID, creds) {
|
|
367
406
|
for resID in listResources().1 {
|
|
368
407
|
creds = access(resID).1
|
|
369
|
-
if resource.urlName == creds.urlName
|
|
370
|
-
&& (!resource.label || resource.label == creds.label)
|
|
371
|
-
&& resource.authName == creds.authName
|
|
408
|
+
if ((!resource.urlName || resource.urlName == creds.urlName)
|
|
409
|
+
&& (!resource.label || resource.label == creds.label))
|
|
372
410
|
return (resID)
|
|
373
411
|
}
|
|
374
412
|
false
|
|
375
413
|
}
|
|
376
414
|
|
|
377
|
-
|
|
415
|
+
|
|
416
|
+
// writeResource
|
|
378
417
|
//
|
|
379
|
-
// Add credentials for a named resource.
|
|
418
|
+
// Add or update credentials for a named resource. If no resID is specified this adds a new
|
|
419
|
+
// resource; otherwise it updates an existing one. The resource is a dictionary comprising these
|
|
420
|
+
// keys:
|
|
380
421
|
// label - [optional] label we use for this resource
|
|
381
422
|
// urlName - URL (e.g. "http://host.com/node/fsapi")
|
|
382
|
-
//
|
|
383
|
-
// authPW - [optional] the autentication password, required if authname is provided
|
|
423
|
+
// authSecret - access-control token for this URL
|
|
384
424
|
// hidden - [optional] don't enumerate to user
|
|
385
425
|
// locked - [optional] don't allow user delete
|
|
386
426
|
//
|
|
387
|
-
// The return value is (error, resID) tuple. Error, if non-false, is a dictionary of field
|
|
427
|
+
// The return value is an (error, resID) tuple. Error, if non-false, is a dictionary of field
|
|
388
428
|
// keys and error diagnostic strings.
|
|
389
|
-
connector.
|
|
429
|
+
connector.writeResource = function writeResource(resource, resID,
|
|
430
|
+
local creds, errors, error, data, change) {
|
|
431
|
+
// badField - test for a bad string
|
|
390
432
|
function badField(str) { !string(str) || str.trim().length == 0 }
|
|
433
|
+
|
|
391
434
|
creds = { urlName: resource.urlName }
|
|
392
435
|
errors = { }
|
|
393
436
|
if resource.label
|
|
@@ -396,13 +439,13 @@ closure psmcFsConnector(psm, nicc, local connClassID, connector, watch) {
|
|
|
396
439
|
creds.label = resource.urlName
|
|
397
440
|
if badField(creds.label)
|
|
398
441
|
errors.label = "invalid label"
|
|
442
|
+
else if !resID && findResource({ label: creds.label })
|
|
443
|
+
errors.label = "duplicate name"
|
|
399
444
|
if badField(resource.urlName)
|
|
400
445
|
errors.urlName = "required field"
|
|
401
|
-
if
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
if badField(resource.authPW)
|
|
405
|
-
errors.authPW = "required if Auth Name specified" }
|
|
446
|
+
if badField(resource.authSecret)
|
|
447
|
+
errors.authSecret = "required field"
|
|
448
|
+
creds.authSecret = resource.authSecret
|
|
406
449
|
if length(errors) > 0
|
|
407
450
|
error = errors
|
|
408
451
|
else {
|
|
@@ -410,14 +453,36 @@ closure psmcFsConnector(psm, nicc, local connClassID, connector, watch) {
|
|
|
410
453
|
creds.hidden = resource.hidden
|
|
411
454
|
if resource.locked
|
|
412
455
|
creds.locked = resource.locked
|
|
413
|
-
resID
|
|
414
|
-
|
|
456
|
+
if resID {
|
|
457
|
+
`(error, data) = connector.vault.updateResource(resID, creds)
|
|
458
|
+
change = { changed: [resID] }
|
|
459
|
+
} else {
|
|
460
|
+
resID = UUID()
|
|
461
|
+
`(error, data) = connector.vault.addResource(resID, creds)
|
|
462
|
+
change = { added: [resID] }
|
|
463
|
+
}
|
|
415
464
|
if data {
|
|
416
|
-
watch.notify(connClassID,
|
|
417
|
-
data = resID
|
|
465
|
+
watch.notify(connClassID, change)
|
|
466
|
+
data = resID
|
|
467
|
+
}
|
|
468
|
+
}
|
|
418
469
|
list(error, data)
|
|
419
470
|
}
|
|
420
|
-
|
|
471
|
+
|
|
472
|
+
// addResource
|
|
473
|
+
//
|
|
474
|
+
// Add a new resource, returning a standard error tuple per writeResource.
|
|
475
|
+
connector.addResource = function addResource(resource) {
|
|
476
|
+
writeResource(resource)
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// updateResource
|
|
480
|
+
//
|
|
481
|
+
// Update an existing resource, returning a standard error tuple per writeResource.
|
|
482
|
+
connector.updateResource = function updateResource(resID, resource) {
|
|
483
|
+
writeResource(resource, resID)
|
|
484
|
+
}
|
|
485
|
+
|
|
421
486
|
// getResource
|
|
422
487
|
//
|
|
423
488
|
// Get credentials for a named resource, matching the dictionary semantics of addResource. The
|
|
@@ -432,10 +497,8 @@ closure psmcFsConnector(psm, nicc, local connClassID, connector, watch) {
|
|
|
432
497
|
}
|
|
433
498
|
if string(creds.urlName)
|
|
434
499
|
resource.urlName = creds.urlName
|
|
435
|
-
if string(creds.
|
|
436
|
-
resource.
|
|
437
|
-
if string(creds.authPW)
|
|
438
|
-
resource.authPW = creds.authPW
|
|
500
|
+
if string(creds.authSecret)
|
|
501
|
+
resource.authSecret = creds.authSecret
|
|
439
502
|
list(false, resource)
|
|
440
503
|
}
|
|
441
504
|
|
|
@@ -510,7 +573,7 @@ closure psmcFsConnector(psm, nicc, local connClassID, connector, watch) {
|
|
|
510
573
|
if creds == "HostFS"
|
|
511
574
|
api = connector.api
|
|
512
575
|
else
|
|
513
|
-
|
|
576
|
+
api = MakeNideAPIclient(creds.urlName, creds.authSecret) // API to remote NodeJS filesystem
|
|
514
577
|
}
|
|
515
578
|
if error
|
|
516
579
|
list(error)
|
|
@@ -256,6 +256,8 @@ TextEncoder = false;
|
|
|
256
256
|
TextDecoder = false;
|
|
257
257
|
EncodeURIComponent = false;
|
|
258
258
|
DecodeURIComponent = false;
|
|
259
|
+
EncodeBase64 = false;
|
|
260
|
+
DecodeBase64 = false;
|
|
259
261
|
JSONstringify = false;
|
|
260
262
|
JSONparse = false;
|
|
261
263
|
|
|
@@ -289,6 +291,10 @@ function comrInit(local manifest) {
|
|
|
289
291
|
EncodeURIComponent = wsg.encodeURIComponent
|
|
290
292
|
DecodeURIComponent = wsg.decodeURIComponent
|
|
291
293
|
//
|
|
294
|
+
// everywhere: Base65
|
|
295
|
+
EncodeBase64 = wsg.btoa
|
|
296
|
+
DecodeBase64 = wsg.atob
|
|
297
|
+
//
|
|
292
298
|
// everywhere: JSON
|
|
293
299
|
JSONstringify = wsg.JSON.stringify
|
|
294
300
|
JSONparse = wsg.JSON.parse
|
|
@@ -338,7 +344,7 @@ function comrInit(local manifest) {
|
|
|
338
344
|
//
|
|
339
345
|
DecodeBase64url = function decodeBase64url(base64url, local padding) {
|
|
340
346
|
base64url = base64url.replace(RegExp("-", "g"), '+').replace(RegExp("_", "g"), '/')
|
|
341
|
-
|
|
347
|
+
DecodeBase64(base64url)
|
|
342
348
|
}
|
|
343
349
|
//
|
|
344
350
|
// For browser windows and web workers
|
|
@@ -358,7 +364,7 @@ function comrInit(local manifest) {
|
|
|
358
364
|
//
|
|
359
365
|
// HashMD5 in base64
|
|
360
366
|
HashMD5_base64 = function browserMD5_base64(data) {
|
|
361
|
-
|
|
367
|
+
EncodeBase64(browserMD5(data, true)) }
|
|
362
368
|
//
|
|
363
369
|
// browserDigest - only in secure contexts (localhost and HTTPS)
|
|
364
370
|
//
|
|
@@ -431,6 +437,8 @@ function comrInit(local manifest) {
|
|
|
431
437
|
HashMD5 =
|
|
432
438
|
HashMD5_base64 =
|
|
433
439
|
HashSHA1 =
|
|
440
|
+
HashSHA256 =
|
|
441
|
+
HashSHA256_base64 =
|
|
434
442
|
RandomBytes = function() { throw(Error("crypto functions unavailable")) }
|
|
435
443
|
}
|
|
436
444
|
}
|
|
@@ -442,6 +450,8 @@ function comrInit(local manifest) {
|
|
|
442
450
|
modobj.exports.TextDecoder = TextDecoder
|
|
443
451
|
modobj.exports.EncodeURIComponent = EncodeURIComponent
|
|
444
452
|
modobj.exports.DecodeURIComponent = DecodeURIComponent
|
|
453
|
+
modobj.exports.EncodeBase64 = EncodeBase64
|
|
454
|
+
modobj.exports.DecodeBase64 = DecodeBase64
|
|
445
455
|
modobj.exports.JSONstringify = JSONstringify
|
|
446
456
|
modobj.exports.JSONparse = JSONparse
|
|
447
457
|
modobj.exports.JsonStringify = JsonStringify
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* column positioning: // // !
|
|
8
8
|
*
|
|
9
|
-
* Copyright (c) 2017-
|
|
9
|
+
* Copyright (c) 2017-2022 by Richard C. Zulch
|
|
10
10
|
*
|
|
11
11
|
*/
|
|
12
12
|
|
|
@@ -36,6 +36,7 @@ closure MakeAPI(port, options, callback, local chroot, server) {
|
|
|
36
36
|
server.psm = require("./psm_server.nlg").MakeServerPSM(server)
|
|
37
37
|
server.root = chroot
|
|
38
38
|
server.app = express()
|
|
39
|
+
server.guid = options.guid
|
|
39
40
|
server.notifyq = []
|
|
40
41
|
server.responseq = []
|
|
41
42
|
server.projects = { }
|
|
@@ -99,8 +100,9 @@ closure MakeAPI(port, options, callback, local chroot, server) {
|
|
|
99
100
|
// body parsing
|
|
100
101
|
//
|
|
101
102
|
|
|
102
|
-
server.app.use(bodyParser.
|
|
103
|
-
server.app.use(bodyParser.
|
|
103
|
+
server.app.use(bodyParser.json({limit: "5mb"}))
|
|
104
|
+
server.app.use(bodyParser.text({limit: "25mb"}))
|
|
105
|
+
server.app.use(bodyParser.raw({limit: "25mb"}))
|
|
104
106
|
|
|
105
107
|
//
|
|
106
108
|
// Express.js endpoints
|
|
@@ -121,15 +123,18 @@ closure MakeAPI(port, options, callback, local chroot, server) {
|
|
|
121
123
|
// "/"
|
|
122
124
|
|
|
123
125
|
server.app.get("/", function(req, res) {
|
|
124
|
-
res.send("<u>
|
|
126
|
+
res.send("<u>naan-server API</u><br>\r\n"
|
|
125
127
|
" /readfile?path=<i>filepath</i><br>\r\n"
|
|
126
128
|
" /status?timeout=<i>msec</i>&after=<i>stamp</i><br>\r\n")
|
|
127
129
|
})
|
|
128
130
|
|
|
129
131
|
// "/readfile"
|
|
130
132
|
|
|
131
|
-
server.app.get("/readfile", closure(req, res) {
|
|
132
|
-
|
|
133
|
+
server.app.get("/readfile", closure(req, res, local guid) {
|
|
134
|
+
guid = req.get("x-naanlang-api-guid")
|
|
135
|
+
if server.guid && guid != server.guid
|
|
136
|
+
res.status(403).send("unauthorized")
|
|
137
|
+
else if not string(req.query.path)
|
|
133
138
|
res.status(400).send("Invalid filename")
|
|
134
139
|
else if RegExp("^\\.\\.[/\\\\]|[/\\\\]\\.\\.$|[/\\\\]\\.\\.[/\\\\]").test(req.query.path)
|
|
135
140
|
res.status(403).send("\"Parent path references forbidden\"")
|
|
@@ -156,7 +161,10 @@ closure MakeAPI(port, options, callback, local chroot, server) {
|
|
|
156
161
|
|
|
157
162
|
// "/status"
|
|
158
163
|
|
|
159
|
-
server.app.get("/status", closure(req,res, local timeoutms, after, responder) {
|
|
164
|
+
server.app.get("/status", closure(req, res, local guid, timeoutms, after, responder) {
|
|
165
|
+
guid = req.get("x-naanlang-api-guid")
|
|
166
|
+
if server.guid && guid != server.guid
|
|
167
|
+
res.status(403).send("unauthorized")
|
|
160
168
|
timeoutms = toint(req.query.timeout)
|
|
161
169
|
after = toint(req.query.after)
|
|
162
170
|
if not integer(timeoutms) or timeoutms > 10000
|
|
@@ -187,8 +195,11 @@ closure MakeAPI(port, options, callback, local chroot, server) {
|
|
|
187
195
|
|
|
188
196
|
// "/psm"
|
|
189
197
|
|
|
190
|
-
server.app.all("/psm", closure(req, res) {
|
|
191
|
-
|
|
198
|
+
server.app.all("/psm", closure(req, res, local guid) {
|
|
199
|
+
guid = req.get("x-naanlang-api-guid")
|
|
200
|
+
if server.guid && guid != server.guid
|
|
201
|
+
res.status(403).send("unauthorized")
|
|
202
|
+
else if !server.hostfs
|
|
192
203
|
res.status(503).send("host filesystem not available")
|
|
193
204
|
else
|
|
194
205
|
server.hostfs.api(req, res)
|
|
@@ -227,7 +238,6 @@ closure MakeAPI(port, options, callback, local chroot, server) {
|
|
|
227
238
|
server.ws = WebSocketServer(server)
|
|
228
239
|
server.port = port
|
|
229
240
|
callback(false, port, server) // notify of success
|
|
230
|
-
debuglog("server open on port", port)
|
|
231
241
|
result = server.psm.conns.NodeFS.connect("Host", "NideFS", list("")) // ### this should go through resource tracker
|
|
232
242
|
if result.0
|
|
233
243
|
ErrorDebuglog(Error("can't access HostFS", result.0))
|
|
@@ -264,7 +274,7 @@ closure WebSocketServer(server, local websocks) {
|
|
|
264
274
|
// Event handlers
|
|
265
275
|
|
|
266
276
|
websocks.wss.on("connection", function(socket, request) {
|
|
267
|
-
websocks.conns.push(WesCon(websocks, socket, request))
|
|
277
|
+
websocks.conns.push(WesCon(server, websocks, socket, request))
|
|
268
278
|
})
|
|
269
279
|
|
|
270
280
|
server.wss.on("error", function(error) {
|
|
@@ -303,7 +313,7 @@ closure WebSocketServer(server, local websocks) {
|
|
|
303
313
|
*
|
|
304
314
|
*/
|
|
305
315
|
|
|
306
|
-
closure WesCon(websocks, socket, request, local wescon) {
|
|
316
|
+
closure WesCon(server, websocks, socket, request, local wescon) {
|
|
307
317
|
wescon = new(object, this)
|
|
308
318
|
wescon.socket = socket
|
|
309
319
|
wescon.serverIDs = []
|
|
@@ -315,7 +325,9 @@ closure WesCon(websocks, socket, request, local wescon) {
|
|
|
315
325
|
socket.on("message", function onmessage(text, local message, error) {
|
|
316
326
|
try {
|
|
317
327
|
message = new(js.g.JSON.parse(text))
|
|
318
|
-
if
|
|
328
|
+
if server.guid && message.guid != server.guid
|
|
329
|
+
error = Error("unauthorized")
|
|
330
|
+
else if message.clientID && websocks.subsystems[message.serverID] {
|
|
319
331
|
wescon.serverIDs.push(message.serverID) // ### track subsystems for closing
|
|
320
332
|
websocks.subsystems[message.serverID].wsReceive(message, wescon)
|
|
321
333
|
}
|