@flowfuse/nr-launcher 1.13.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.
Files changed (40) hide show
  1. package/CHANGELOG.md +182 -0
  2. package/LICENSE +178 -0
  3. package/README.md +28 -0
  4. package/index.js +148 -0
  5. package/lib/admin.js +95 -0
  6. package/lib/auditLogger/index.js +41 -0
  7. package/lib/auth/adminAuth.js +77 -0
  8. package/lib/auth/httpAuthMiddleware.js +71 -0
  9. package/lib/auth/httpAuthPlugin.js +10 -0
  10. package/lib/auth/strategy.js +34 -0
  11. package/lib/context/FFContextStorage.js +422 -0
  12. package/lib/context/index.js +9 -0
  13. package/lib/context/memoryCache.js +156 -0
  14. package/lib/launcher.js +695 -0
  15. package/lib/logBuffer.js +57 -0
  16. package/lib/resources/resourcePlugin.js +20 -0
  17. package/lib/resources/sample.js +57 -0
  18. package/lib/resources/sampleBuffer.js +85 -0
  19. package/lib/runtimeSettings.js +320 -0
  20. package/lib/storage/index.js +92 -0
  21. package/lib/storage/libraryPlugin.js +90 -0
  22. package/lib/theme/LICENSE +178 -0
  23. package/lib/theme/README.md +24 -0
  24. package/lib/theme/common/forge-common.css +108 -0
  25. package/lib/theme/common/forge-common.js +75 -0
  26. package/lib/theme/forge-dark/forge-dark-custom.css +2 -0
  27. package/lib/theme/forge-dark/forge-dark-custom.js +1 -0
  28. package/lib/theme/forge-dark/forge-dark-monaco.json +213 -0
  29. package/lib/theme/forge-dark/forge-dark-theme.css +12 -0
  30. package/lib/theme/forge-dark/forge-dark.js +61 -0
  31. package/lib/theme/forge-light/forge-light-custom.css +2 -0
  32. package/lib/theme/forge-light/forge-light-custom.js +1 -0
  33. package/lib/theme/forge-light/forge-light-monaco.json +227 -0
  34. package/lib/theme/forge-light/forge-light-theme.css +12 -0
  35. package/lib/theme/forge-light/forge-light.js +62 -0
  36. package/package.json +72 -0
  37. package/resources/favicon-16x16.png +0 -0
  38. package/resources/favicon-32x32.png +0 -0
  39. package/resources/favicon.ico +0 -0
  40. package/resources/ff-nr.png +0 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,182 @@
1
+ #### 1.13.3: Release
2
+ - Update path to localfs following org rename (#191) @Steve-Mcl
3
+ - Update file nodes to latest (#189) @knolleary
4
+ - Expose user email in session (#188) @hardillb
5
+
6
+ #### 1.13.0: Release
7
+
8
+ - Fixes node path for k8s/docker environments (#186) @knolleary
9
+ - FIX: Dispatch node-red image rebuild after successful package publish (#185) @ppawlowski
10
+ - Update project nodes for new org (#183) @knolleary
11
+ - Pin reusable workflows to v0.1.0 (#184) @ppawlowski
12
+ - Update to use @flowfuse/nr-file-nodes (#182) @knolleary
13
+ - Remove unused workflow (#181) @knolleary
14
+ - Bump build and publish workflow versions (#180) @ppawlowski
15
+ - Move nr-persistent-context into nr-launcher (#179) @knolleary
16
+ - Add tests and fix error samples (#178) @hardillb
17
+ - Resource monitoring and alerts (#176) @hardillb
18
+ - Update branding in theme menu items (#177) @knolleary
19
+ - Update ff references in package.json (#174) @knolleary
20
+ - Change repo references in workflows after github org rename (#169) @ppawlowski
21
+
22
+ #### 1.12.0: Release
23
+
24
+ - Fix tests on windows - ensure forward slashes on paths (#172) @Steve-Mcl
25
+ - Bumping version (#170) @hardillb
26
+ - Add support for custom node catalogues (#162) @hardillb
27
+ - Publish nightly package to npmjs (#168) @ppawlowski
28
+
29
+ #### 1.11.0: Release
30
+
31
+ - Use feature flag to enable shared library (#156) @knolleary
32
+ - Enable localfs package build dispatcher after package publish (#160) @ppawlowski
33
+ - Update icon (#158) @Yndira-FlowForge
34
+ - FIX: Publish package on push to `main` and on schedule (#155) @ppawlowski
35
+ - Enable tests on build; refactor `ignore-scripts` approach (#154) @ppawlowski
36
+ - Introduce publish pipeline (#143) @ppawlowski
37
+
38
+ #### 1.10.0: Release
39
+
40
+ - Ensure TimeZone is passed to NR (#151) @hardillb
41
+ - Fix node_path when running in dev-env (#150) @knolleary
42
+ - Fix wait on deferredStop when trying to start a stopping instance (#147) @knolleary
43
+ - settings: Inject custom catalogues into NR settings (#146) @ZJvandeWeg
44
+ - Chore: Set root flag in eslint (#142) @Pezmc
45
+ - Prevent NODE_RED_ENABLE_PROJECTS (#141) @hardillb
46
+ - Fix theme build step (#139) @hardillb
47
+
48
+ #### 1.9.0: Release
49
+
50
+ - Version bump sub project `nr-theme` for initial (manual) publish (#137) @Steve-Mcl
51
+ - Publish theme as seperate package (#136) @hardillb
52
+ - Add package lock.json (#135) @hardillb
53
+ - Add src attribute to launcher log entries (#133) @hardillb
54
+ - Change oauth scope for httpNode middleware requests (#132) @knolleary
55
+ - Update health poll to use 127.0.0.1 address (#129) @knolleary
56
+
57
+ #### 1.8.0: Release
58
+
59
+ - Update dependencies (#124) @hardillb
60
+ - Pass HA flag to project nodes if enabled (#123) @knolleary
61
+ - Disable the editor if HA enabled (#122) @hardillb
62
+ - Set IPv4 first flag (#120) @hardillb
63
+ - Make NR listen on IPv6 as well as IPv4 (#119) @hardillb
64
+ - Ensure HOME env var set if present (#118) @hardillb
65
+ - Increase number of startup polls allowed to fail for hang detection (#116) @knolleary
66
+
67
+ #### 1.7.0: Release
68
+
69
+ - Allow more failed pings during startup to avoid slow starts getting killed (#113) @knolleary
70
+ - Detect hung node-red via regularly polling (#112) @knolleary
71
+ - Ensure Node-RED process is stopped before attempting restart (#111) @knolleary
72
+
73
+ #### 1.6.0: Release
74
+
75
+ - Resolve theme selection issue (#108) @Steve-Mcl
76
+
77
+ #### 1.5.0: Release
78
+
79
+ - Improve crash loop detection (#106) @Steve-Mcl
80
+ - Allow Private CA Certs bundle to be passed to Node-RED (#105) @hardillb
81
+
82
+ #### 1.4.0: Release
83
+
84
+ - Bump nr-peresistent-context nodes (#103) @hardillb
85
+ - Move storage/auth/auditLogger/theme into launcher (#100) @knolleary
86
+
87
+ #### 1.3.0: Release
88
+
89
+ - Bump project nodes version (#97) @hardillb
90
+ - Separate out Dashboard middleware handling (#96) @knolleary
91
+ - Add auth and storage to node-red nodeDir (#95) @knolleary
92
+ - Improve stuck intermediate state of project (#94) @Steve-Mcl
93
+ - Add Team Library configuration settings (#93) @knolleary
94
+ - Add support for httpNodeMiddleware and FlowForge User auth (#92) @knolleary
95
+
96
+ #### 1.2.0: Release
97
+
98
+ - Bump plugin versions (#90) @hardillb
99
+ - Ensure allow/deny lists default to proper values (#87) @knolleary
100
+ - Add settings for persistent storage (#86) @Steve-Mcl
101
+
102
+ #### 1.1.0: Release
103
+
104
+ - Bump nr-file-node version (#84) @hardillb
105
+ - Add nr-file-nodes as dep (#83) @hardillb
106
+ - Add fileStore settings for @flowforge/file-storage (#82) @Steve-Mcl
107
+ - Implement tcp/udp allow/inhibit settings (#81) @Steve-Mcl
108
+
109
+ #### 1.0.0: Release
110
+
111
+ - Closes a timing window on slow starting systems (#79) @hardillb
112
+ - Fix npm on windows (#78) @Steve-Mcl
113
+ - Npm install starting (#75) @hardillb
114
+ - Remove unwanted debug (#76) @knolleary
115
+ - Have loadSettings fail gracefully (#74) @hardillb
116
+ - Update eslint (#73) @knolleary
117
+ - Get the list of package.json modules from project settings (#72) @knolleary
118
+ - Back out #70 (#71) @hardillb
119
+ - Remove the explicit paths to theme (#70) @hardillb
120
+
121
+ #### 0.10.0: Release
122
+
123
+ - Only write httpNodeAuth if non-blank user/pass are provided (#67) @knolleary
124
+ - Add flag to disable Node-RED Welcome Tours (#66) @hardillb
125
+ - Allow the setting of httpNodeAuth (#64) @hardillb
126
+ - Improve accuracy of the stopped/running status indicator following a restart (#65) @Steve-Mcl
127
+
128
+ #### 0.9.0: Release
129
+
130
+ - permit custom dashboard path to be set from FF (#62) @Steve-Mcl
131
+ - Add launcherVersion for both front and backend (#61) @Steve-Mcl
132
+
133
+ #### 0.8.0: Release
134
+
135
+ - add runtimeState (#58) @sammachin
136
+ - add dep @flowforge/nr-project-nodes (#56) @Steve-Mcl
137
+ - Add FORGE_LICENSE_TYPE env so launcher can enable EE only features (#59) @knolleary
138
+ - Ensure broker details are passed through to settings file (#57) @knolleary
139
+ - Map through settings for project links (#53) @Steve-Mcl
140
+ - Fix search path for theme (#52) @hardillb
141
+
142
+ #### 0.7.0: Release
143
+
144
+ - Add some initial tests (#49) @knolleary
145
+ - Remove Node-RED as a direct dependency (#48) @hardillb
146
+ - Fix node denyList and set up module denyList (#46) @hardillb
147
+ - Initial theming support (#37) @Steve-Mcl
148
+ - Add "trust proxy" to settings.js to improve client IP detection (#45) @Steve-Mcl
149
+
150
+ #### 0.6.0: Release
151
+
152
+ - Map FlowForge logout to nodered auth/revoke (#40) @Steve-Mcl
153
+ - Update dependencies (#41) @knolleary
154
+ - Report node/nr/launcher versions in /info endpoint response (#39) @knolleary
155
+ - Fix win32 stopping projects and "crash" status (#38) @Steve-Mcl
156
+ - Auto generate credential secret for NR project to remove warnings in log (#36) @Steve-Mcl
157
+
158
+ #### 0.5.0: Release
159
+
160
+ - Redirect user back to ff platform on logout (#34) @knolleary
161
+ - Add palette/module allowList/denyList (#32) @hardillb
162
+ - Put NR into safemode when crash loop detected (#33) @knolleary
163
+
164
+ #### 0.4.0: Release
165
+
166
+ - Update project automation (#28) @knolleary
167
+ - Remove unused logBuffer code (#27) @knolleary
168
+ - Fix lint rules to apply to lib dir (#26) @hardillb
169
+
170
+ #### 0.3.0: Release
171
+
172
+ - Apply project settings to settings.js (#23) @knolleary
173
+ - Use a specific NR version (#22) @hardillb
174
+ - Add eslint rules (#21) @hardillb
175
+ - Add support for max-old-space-size (#20) @knolleary
176
+ - Add launcher's node_modules to NR NODE_PATH (#19) @hardillb
177
+ - Automate npm publish on release (#18) @hardillb
178
+
179
+ #### 0.2.0: Release
180
+
181
+ - Set default editor to monaco (#15) @hardillb
182
+ - Add project workflow automation (#14) @knolleary
package/LICENSE ADDED
@@ -0,0 +1,178 @@
1
+ Copyright FlowForge Inc, and other contributors, https://flowforge.com/
2
+
3
+ Apache License
4
+ Version 2.0, January 2004
5
+ http://www.apache.org/licenses/
6
+
7
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8
+
9
+ 1. Definitions.
10
+
11
+ "License" shall mean the terms and conditions for use, reproduction,
12
+ and distribution as defined by Sections 1 through 9 of this document.
13
+
14
+ "Licensor" shall mean the copyright owner or entity authorized by
15
+ the copyright owner that is granting the License.
16
+
17
+ "Legal Entity" shall mean the union of the acting entity and all
18
+ other entities that control, are controlled by, or are under common
19
+ control with that entity. For the purposes of this definition,
20
+ "control" means (i) the power, direct or indirect, to cause the
21
+ direction or management of such entity, whether by contract or
22
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
23
+ outstanding shares, or (iii) beneficial ownership of such entity.
24
+
25
+ "You" (or "Your") shall mean an individual or Legal Entity
26
+ exercising permissions granted by this License.
27
+
28
+ "Source" form shall mean the preferred form for making modifications,
29
+ including but not limited to software source code, documentation
30
+ source, and configuration files.
31
+
32
+ "Object" form shall mean any form resulting from mechanical
33
+ transformation or translation of a Source form, including but
34
+ not limited to compiled object code, generated documentation,
35
+ and conversions to other media types.
36
+
37
+ "Work" shall mean the work of authorship, whether in Source or
38
+ Object form, made available under the License, as indicated by a
39
+ copyright notice that is included in or attached to the work
40
+ (an example is provided in the Appendix below).
41
+
42
+ "Derivative Works" shall mean any work, whether in Source or Object
43
+ form, that is based on (or derived from) the Work and for which the
44
+ editorial revisions, annotations, elaborations, or other modifications
45
+ represent, as a whole, an original work of authorship. For the purposes
46
+ of this License, Derivative Works shall not include works that remain
47
+ separable from, or merely link (or bind by name) to the interfaces of,
48
+ the Work and Derivative Works thereof.
49
+
50
+ "Contribution" shall mean any work of authorship, including
51
+ the original version of the Work and any modifications or additions
52
+ to that Work or Derivative Works thereof, that is intentionally
53
+ submitted to Licensor for inclusion in the Work by the copyright owner
54
+ or by an individual or Legal Entity authorized to submit on behalf of
55
+ the copyright owner. For the purposes of this definition, "submitted"
56
+ means any form of electronic, verbal, or written communication sent
57
+ to the Licensor or its representatives, including but not limited to
58
+ communication on electronic mailing lists, source code control systems,
59
+ and issue tracking systems that are managed by, or on behalf of, the
60
+ Licensor for the purpose of discussing and improving the Work, but
61
+ excluding communication that is conspicuously marked or otherwise
62
+ designated in writing by the copyright owner as "Not a Contribution."
63
+
64
+ "Contributor" shall mean Licensor and any individual or Legal Entity
65
+ on behalf of whom a Contribution has been received by Licensor and
66
+ subsequently incorporated within the Work.
67
+
68
+ 2. Grant of Copyright License. Subject to the terms and conditions of
69
+ this License, each Contributor hereby grants to You a perpetual,
70
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
71
+ copyright license to reproduce, prepare Derivative Works of,
72
+ publicly display, publicly perform, sublicense, and distribute the
73
+ Work and such Derivative Works in Source or Object form.
74
+
75
+ 3. Grant of Patent License. Subject to the terms and conditions of
76
+ this License, each Contributor hereby grants to You a perpetual,
77
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
78
+ (except as stated in this section) patent license to make, have made,
79
+ use, offer to sell, sell, import, and otherwise transfer the Work,
80
+ where such license applies only to those patent claims licensable
81
+ by such Contributor that are necessarily infringed by their
82
+ Contribution(s) alone or by combination of their Contribution(s)
83
+ with the Work to which such Contribution(s) was submitted. If You
84
+ institute patent litigation against any entity (including a
85
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
86
+ or a Contribution incorporated within the Work constitutes direct
87
+ or contributory patent infringement, then any patent licenses
88
+ granted to You under this License for that Work shall terminate
89
+ as of the date such litigation is filed.
90
+
91
+ 4. Redistribution. You may reproduce and distribute copies of the
92
+ Work or Derivative Works thereof in any medium, with or without
93
+ modifications, and in Source or Object form, provided that You
94
+ meet the following conditions:
95
+
96
+ (a) You must give any other recipients of the Work or
97
+ Derivative Works a copy of this License; and
98
+
99
+ (b) You must cause any modified files to carry prominent notices
100
+ stating that You changed the files; and
101
+
102
+ (c) You must retain, in the Source form of any Derivative Works
103
+ that You distribute, all copyright, patent, trademark, and
104
+ attribution notices from the Source form of the Work,
105
+ excluding those notices that do not pertain to any part of
106
+ the Derivative Works; and
107
+
108
+ (d) If the Work includes a "NOTICE" text file as part of its
109
+ distribution, then any Derivative Works that You distribute must
110
+ include a readable copy of the attribution notices contained
111
+ within such NOTICE file, excluding those notices that do not
112
+ pertain to any part of the Derivative Works, in at least one
113
+ of the following places: within a NOTICE text file distributed
114
+ as part of the Derivative Works; within the Source form or
115
+ documentation, if provided along with the Derivative Works; or,
116
+ within a display generated by the Derivative Works, if and
117
+ wherever such third-party notices normally appear. The contents
118
+ of the NOTICE file are for informational purposes only and
119
+ do not modify the License. You may add Your own attribution
120
+ notices within Derivative Works that You distribute, alongside
121
+ or as an addendum to the NOTICE text from the Work, provided
122
+ that such additional attribution notices cannot be construed
123
+ as modifying the License.
124
+
125
+ You may add Your own copyright statement to Your modifications and
126
+ may provide additional or different license terms and conditions
127
+ for use, reproduction, or distribution of Your modifications, or
128
+ for any such Derivative Works as a whole, provided Your use,
129
+ reproduction, and distribution of the Work otherwise complies with
130
+ the conditions stated in this License.
131
+
132
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
133
+ any Contribution intentionally submitted for inclusion in the Work
134
+ by You to the Licensor shall be under the terms and conditions of
135
+ this License, without any additional terms or conditions.
136
+ Notwithstanding the above, nothing herein shall supersede or modify
137
+ the terms of any separate license agreement you may have executed
138
+ with Licensor regarding such Contributions.
139
+
140
+ 6. Trademarks. This License does not grant permission to use the trade
141
+ names, trademarks, service marks, or product names of the Licensor,
142
+ except as required for reasonable and customary use in describing the
143
+ origin of the Work and reproducing the content of the NOTICE file.
144
+
145
+ 7. Disclaimer of Warranty. Unless required by applicable law or
146
+ agreed to in writing, Licensor provides the Work (and each
147
+ Contributor provides its Contributions) on an "AS IS" BASIS,
148
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
149
+ implied, including, without limitation, any warranties or conditions
150
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
151
+ PARTICULAR PURPOSE. You are solely responsible for determining the
152
+ appropriateness of using or redistributing the Work and assume any
153
+ risks associated with Your exercise of permissions under this License.
154
+
155
+ 8. Limitation of Liability. In no event and under no legal theory,
156
+ whether in tort (including negligence), contract, or otherwise,
157
+ unless required by applicable law (such as deliberate and grossly
158
+ negligent acts) or agreed to in writing, shall any Contributor be
159
+ liable to You for damages, including any direct, indirect, special,
160
+ incidental, or consequential damages of any character arising as a
161
+ result of this License or out of the use or inability to use the
162
+ Work (including but not limited to damages for loss of goodwill,
163
+ work stoppage, computer failure or malfunction, or any and all
164
+ other commercial damages or losses), even if such Contributor
165
+ has been advised of the possibility of such damages.
166
+
167
+ 9. Accepting Warranty or Additional Liability. While redistributing
168
+ the Work or Derivative Works thereof, You may choose to offer,
169
+ and charge a fee for, acceptance of support, warranty, indemnity,
170
+ or other liability obligations and/or rights consistent with this
171
+ License. However, in accepting such obligations, You may act only
172
+ on Your own behalf and on Your sole responsibility, not on behalf
173
+ of any other Contributor, and only if You agree to indemnify,
174
+ defend, and hold each Contributor harmless for any liability
175
+ incurred by, or claims asserted against, such Contributor by reason
176
+ of your accepting any such warranty or additional liability.
177
+
178
+ END OF TERMS AND CONDITIONS
package/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # FlowFuse Launcher for Node-RED
2
+
3
+ This is the launcher FlowFuse uses to run instances of Node-RED. It dynamically
4
+ generates the Node-RED settings based on the associated Project's settings.
5
+
6
+ The launcher starts its own HTTP service to allow the FlowForge platform to remotely
7
+ control it.
8
+
9
+ ### Configure
10
+
11
+ - `--forgeURL` - URL for Forge platform
12
+ - `--port` - port to listen on for management interface
13
+ - `--team` - FlowForge team id UUID
14
+ - `--project` - FlowForge project id UUID
15
+ - `--token` - Bearer Token to access Forge platform
16
+ - `--nodeRedPath` - path to dir with a `node_modules` directory container a version of Node-RED
17
+ - `--no-tcp-in` - inhibit TCP nodes from being servers
18
+ - `--no-udp-in` - inhibit UDP nodes from being servers
19
+
20
+ The following Environment Variables can be used instead of the cmd line args...
21
+
22
+ `FORGE_URL`, `FORGE_TEAM_ID`, `FORGE_PROJECT_ID`, `FORGE_PROJECT_TOKEN`, `FORGE_NR_PATH`, `FORGE_NR_NO_TCP_IN`, `FORGE_NR_NO_UDP_IN`
23
+
24
+ NOTE: cmd line args take precedent if both are provided
25
+
26
+ By default, the launcher does not pass host environment variables through to the Node-RED process; only setting the built-in env vars and those configured in the instance settings.
27
+
28
+ However, if `FORGE_EXPOSE_HOST_ENV` is set, the launcher will pass through all env vars - except that starting with `FORGE_*`.
package/index.js ADDED
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('fs')
3
+ const path = require('path')
4
+ const commandLineArgs = require('command-line-args')
5
+
6
+ const NODE_MAJOR_VERSION = process.versions.node.split('.')[0]
7
+ if (NODE_MAJOR_VERSION > 14) {
8
+ const dns = require('node:dns')
9
+ dns.setDefaultResultOrder('ipv4first')
10
+ }
11
+
12
+ const { Launcher } = require('./lib/launcher')
13
+ const { AdminInterface } = require('./lib/admin')
14
+
15
+ const cmdLineOptions = [
16
+ { name: 'port', alias: 'p', type: Number },
17
+ { name: 'forgeURL', type: String },
18
+ { name: 'team', alias: 't', type: String },
19
+ { name: 'project', type: String },
20
+ { name: 'token', type: String },
21
+ { name: 'buffer', alias: 'b', type: Number },
22
+ { name: 'nodeRedPath', alias: 'n', type: String },
23
+ { name: 'credentialSecret', type: String },
24
+ { name: 'no-tcp-in', alias: 'T', type: Boolean },
25
+ { name: 'no-udp-in', alias: 'U', type: Boolean }
26
+ ]
27
+
28
+ const options = commandLineArgs(cmdLineOptions)
29
+
30
+ options.forgeURL = options.forgeURL || process.env.FORGE_URL
31
+ options.team = options.team || process.env.FORGE_TEAM_ID
32
+ options.project = options.project || process.env.FORGE_PROJECT_ID
33
+ options.token = options.token || process.env.FORGE_PROJECT_TOKEN
34
+ options.logBufferMax = options.logBufferMax || 1000
35
+ options.nodeRedPath = options.nodeRedPath || process.env.FORGE_NR_PATH
36
+
37
+ // Boolean Options
38
+ const parseBoolean = (val, _default) => {
39
+ if (val === true || val === false) { return val }
40
+ if (val === 'true' || val === 'TRUE') { return true }
41
+ if (val === 'false' || val === 'FALSE') { return false }
42
+ return _default
43
+ }
44
+ const noTcp = parseBoolean(options['no-tcp-in'], parseBoolean(process.env.FORGE_NR_NO_TCP_IN), undefined)
45
+ const noUdp = parseBoolean(options['no-udp-in'], parseBoolean(process.env.FORGE_NR_NO_UDP_IN), undefined)
46
+ options.allowInboundTcp = noTcp === undefined ? undefined : !noTcp
47
+ options.allowInboundUdp = noUdp === undefined ? undefined : !noTcp
48
+
49
+ if (process.env.FORGE_BROKER_URL && process.env.FORGE_BROKER_USERNAME && process.env.FORGE_BROKER_PASSWORD) {
50
+ options.broker = {
51
+ url: process.env.FORGE_BROKER_URL,
52
+ username: process.env.FORGE_BROKER_USERNAME,
53
+ password: process.env.FORGE_BROKER_PASSWORD
54
+ }
55
+ }
56
+
57
+ const ext = process.platform === 'win32' ? '.cmd' : ''
58
+
59
+ options.execPath = undefined
60
+ if (options.nodeRedPath) {
61
+ options.execPath = path.join(options.nodeRedPath, 'node_modules', '.bin', `node-red${ext}`)
62
+ if (!fs.existsSync(options.execPath)) {
63
+ options.execPath = undefined
64
+ }
65
+ }
66
+ if (!options.execPath) {
67
+ // Find the bundled version
68
+ for (let i = 0; i < require.main.paths.length; i++) {
69
+ const execPath = path.join(require.main.paths[i], '.bin', `node-red${ext}`)
70
+ if (fs.existsSync(execPath)) {
71
+ options.execPath = execPath
72
+ break
73
+ }
74
+ }
75
+ }
76
+
77
+ if (!options.execPath) {
78
+ console.log(require.main.paths)
79
+ console.log('executable not found')
80
+ process.exit(1)
81
+ }
82
+
83
+ // Gather versions numbers for reporting to the platform
84
+ options.versions = {
85
+ node: process.version.replace(/^v/, ''),
86
+ launcher: require('./package.json').version
87
+ }
88
+
89
+ // Go find Node-RED's package.json
90
+ const nrModulePath = path.relative(__dirname, path.join(path.dirname(options.execPath), '..', 'node-red', 'package.json'))
91
+ try {
92
+ const nrPkg = require(nrModulePath)
93
+ options.versions['node-red'] = nrPkg.version
94
+ } catch (err) {
95
+ options.versions['node-red'] = err.toString()
96
+ }
97
+
98
+ async function main () {
99
+ const launcher = new Launcher(options)
100
+ const adminInterface = new AdminInterface(options, launcher)
101
+ adminInterface.start()
102
+
103
+ process.on('SIGTERM', async () => {
104
+ await launcher.stop()
105
+ process.exit(0)
106
+ })
107
+ try {
108
+ await launcher.loadSettings()
109
+ await launcher.start()
110
+ } catch (error) {
111
+ await launcher.logAuditEvent('start-failed', { error })
112
+ }
113
+
114
+ // const wss = new ws.Server({ clientTracking: false, noServer: true })
115
+ //
116
+ // server.on('upgrade', (req, socket, head) => {
117
+ // if (req.url === '/flowforge/logs') {
118
+ // wss.handleUpgrade(req, socket, head, (ws) => {
119
+ // wss.emit('connection', ws, req)
120
+ // })
121
+ // }
122
+ // })
123
+ //
124
+ //
125
+ // wss.on('connection', (ws, req) => {
126
+ // logBuffer.forEach(log => {
127
+ // if (log) {
128
+ // ws.send(log)
129
+ // }
130
+ // })
131
+ //
132
+ // function wsLogSend(msg) {
133
+ // ws.send(msg)
134
+ // }
135
+ //
136
+ // logEmmiter.on('log', wsLogSend)
137
+ //
138
+ // ws.on('close', () => {
139
+ // logEmmiter.removeListener('log',wsLogSend)
140
+ // })
141
+ // })
142
+ //
143
+ //
144
+ // let settings = await getSettings()
145
+ // await start(settings)
146
+ }
147
+
148
+ main()
package/lib/admin.js ADDED
@@ -0,0 +1,95 @@
1
+ const http = require('http')
2
+ const express = require('express')
3
+ const bodyParser = require('body-parser')
4
+ const { States } = require('./launcher')
5
+
6
+ class AdminInterface {
7
+ constructor (options, launcher) {
8
+ this.options = options
9
+ this.launcher = launcher
10
+
11
+ const app = express()
12
+ this.server = http.createServer(app)
13
+
14
+ app.use(bodyParser.json({}))
15
+ app.use(bodyParser.text({}))
16
+
17
+ app.get('/flowforge/info', (request, response) => {
18
+ const info = {
19
+ id: this.options.project,
20
+ state: this.launcher.getState(),
21
+ lastStartTime: this.launcher.getLastStartTime(),
22
+ versions: options.versions
23
+ }
24
+ response.send(info)
25
+ })
26
+
27
+ app.get('/flowforge/logs', (request, response) => {
28
+ response.send(this.launcher.getLog().toArray())
29
+ })
30
+
31
+ app.get('/flowforge/resources', (request, response) => {
32
+ response.send(this.launcher.getResources().toArray())
33
+ })
34
+
35
+ app.get('/flowforge/health-check', (request, response) => {
36
+ if (this.launcher.isHealthy()) {
37
+ response.sendStatus(200)
38
+ } else {
39
+ response.sendStatus(500)
40
+ }
41
+ })
42
+
43
+ app.post('/flowforge/command', async (request, response) => {
44
+ if (request.body.cmd === 'stop') {
45
+ launcher.stop()
46
+ response.send({})
47
+ // } else {
48
+ // response.status(409).send({err: "Not running"})
49
+ // }
50
+ } else if (request.body.cmd === 'restart') {
51
+ await launcher.stop()
52
+ setTimeout(async () => {
53
+ // Update the settings
54
+ try {
55
+ await launcher.loadSettings()
56
+ await launcher.start(request.body.safe ? States.SAFE : States.RUNNING)
57
+ } catch (error) {
58
+ await launcher.logAuditEvent('start-failed', { error })
59
+ }
60
+ response.send({})
61
+ }, 2000)
62
+ } else if (request.body.cmd === 'start') {
63
+ if (launcher.getState() === States.RUNNING) {
64
+ response.status(409).send({ err: 'Already running' })
65
+ } else {
66
+ try {
67
+ await launcher.loadSettings()
68
+ await launcher.start(request.body.safe ? States.SAFE : States.RUNNING)
69
+ } catch (error) {
70
+ // delay error audit entry to allow the start command to return and be logged first
71
+ setTimeout(() => {
72
+ launcher?.logAuditEvent && launcher.logAuditEvent('start-failed', { error })
73
+ }, 100)
74
+ }
75
+ response.send({})
76
+ }
77
+ } else if (request.body.cmd === 'logout') { // logout:nodered(step-4)
78
+ await launcher.revokeUserToken(request.body.token) // logout:nodered(step-5)
79
+ response.send({})
80
+ } else if (request.body.cmd === 'shutdown') {
81
+ await launcher.stop()
82
+ response.send({})
83
+ process.exit(0)
84
+ } else {
85
+ response.status(404).send({})
86
+ }
87
+ })
88
+ }
89
+
90
+ start () {
91
+ this.server.listen(this.options.port)
92
+ }
93
+ }
94
+
95
+ module.exports = { AdminInterface }
@@ -0,0 +1,41 @@
1
+ /**
2
+ *
3
+ */
4
+
5
+ const got = require('got')
6
+
7
+ module.exports = (settings) => {
8
+ const baseURL = settings.loggingURL
9
+ const projectID = settings.projectID
10
+ const token = settings.token
11
+
12
+ const logger = function (msg) {
13
+ if (/^(comms\.|.*\.get$)/.test(msg.event)) {
14
+ // Ignore comms events and any .get event that is just reading data
15
+ return
16
+ }
17
+ if (/^auth/.test(msg.event) && !/^auth.log/.test(msg.event)) {
18
+ return
19
+ }
20
+ if (msg.user) {
21
+ msg.user = msg.user.userId
22
+ }
23
+ delete msg.username
24
+ delete msg.level
25
+
26
+ got.post(baseURL + '/' + projectID + '/audit', {
27
+ json: msg,
28
+ responseType: 'json',
29
+ headers: {
30
+ 'user-agent': 'FlowFuse Audit Logging v0.1',
31
+ authorization: 'Bearer ' + token
32
+ }
33
+ })
34
+ .catch(err => {
35
+ // ignore errors for now
36
+ console.log(err)
37
+ })
38
+ }
39
+
40
+ return logger
41
+ }