Closed Steve-Mcl closed 1 month ago
Ben spoke up about possible environments where setting a proxy may be necessary for access to external resources but not the forge backend (and vice versa)
We discussed the implementation should be aware of the no_proxy
env var or perhaps use separate env vars (e.g. ff_device_http_proxy).
Supporting no_proxy
was determined to be the most obvious first choice since it does not need describing or documenting due to being a well known "thing".
Switching PR to draft while I evaluate the options.
@hardillb this is now ready for local testing.
I had a strange issue when connecting the Device Editor tunnel with NR4-beta.4
import('got')
did not work in the devices settings.js
In the end, I had to add fall back to non esm GOT if not found to get past this.
template-settings.js calls import('got')
doesnt work!
require.resolve('got')
-> 'C:\\Users\\Stephen\\repos\\github\\flowfuse\\dev-env\\packages\\device-agent\\node_modules\\got\\dist\\source\\index.js'
(this is GOT v11 see npm list below)require.resolve('got')
-> 'C:\\opt\\flowfuse-device\\project\\node_modules\\got\\dist\\source\\index.js'
(this is GOT v12.6.0)_NOTE: NODE_PATH
was set to the device-agent node_modules
so that the NR plugins (auth, library access) can find http-proxy-agent
& proxy-from-env
which is required for proxies_
process.cwd()
: 'C:\opt\flowfuse-device\project'process.cwd()
: 'C:\opt\flowfuse-device\project'process.env.NODE_PATH
: 'C:\opt\flowfuse-device\project\node_modules;C:\Users\Stephen\repos\github\flowfuse\dev-env\packages\device-agent\node_modules'process.env.NODE_PATH
: 'C:\opt\flowfuse-device\project\node_modules;C:\Users\Stephen\repos\github\flowfuse\dev-env\packages\device-agent\node_modules'require.main.paths
0: 'C:\opt\flowfuse-device\project\node_modules\node-red\node_modules'
1: 'C:\opt\flowfuse-device\project\node_modules'
2: 'C:\opt\flowfuse-device\node_modules'
3: 'C:\opt\node_modules'
4: 'C:\node_modules'require.main.paths
0: 'C:\opt\flowfuse-device\project\node_modules\node-red\node_modules'
1: 'C:\opt\flowfuse-device\project\node_modules'
2: 'C:\opt\flowfuse-device\node_modules'
3: 'C:\opt\node_modules'
4: 'C:\node_modules'npm list got
(NR 4)
project@0.0.0-0 C:\opt\flowfuse-device\project
├─┬ @flowfuse/nr-project-nodes@0.6.4
│ └── got@11.8.6
└─┬ node-red@4.0.0-beta.4
└─┬ @node-red/nodes@4.0.0-beta.4
└── got@12.6.0
npm list got
(NR 3.1.0)
project@0.0.0-0 C:\opt\flowfuse-device\project
├─┬ @flowfuse/nr-project-nodes@0.6.4
│ └── got@11.8.6
└─┬ node-red@3.1.10
└─┬ @node-red/nodes@3.1.10
└── got@12.6.0
call stack when settings.js tokens()
is called:
Object.tokens (c:\opt\flowfuse-device\project\settings.js:61)
Object.tokens (c:\opt\flowfuse-device\project\node_modules\@node-red\editor-api\lib\auth\users.js:132)
<anonymous> (c:\opt\flowfuse-device\project\node_modules\@node-red\editor-api\lib\auth\strategies.js:148)
global.authenticateUserToken (c:\opt\flowfuse-device\project\node_modules\@node-red\editor-api\lib\auth\strategies.js:133)
TokensStrategy.authenticate (c:\opt\flowfuse-device\project\node_modules\@node-red\editor-api\lib\auth\strategies.js:168)
global.attempt (c:\opt\flowfuse-device\project\node_modules\passport\lib\middleware\authenticate.js:378)
strategy.fail (c:\opt\flowfuse-device\project\node_modules\passport\lib\middleware\authenticate.js:314)
global.verified (c:\opt\flowfuse-device\project\node_modules\passport-http-bearer\lib\strategy.js:124)
<anonymous> (c:\opt\flowfuse-device\project\node_modules\@node-red\editor-api\lib\auth\strategies.js:44)
Promise.then (Unknown Source:0)
bearerStrategy (c:\opt\flowfuse-device\project\node_modules\@node-red\editor-api\lib\auth\strategies.js:32)
Strategy.authenticate (c:\opt\flowfuse-device\project\node_modules\passport-http-bearer\lib\strategy.js:132)
attempt (c:\opt\flowfuse-device\project\node_modules\passport\lib\middleware\authenticate.js:378)
authenticate (c:\opt\flowfuse-device\project\node_modules\passport\lib\middleware\authenticate.js:379)
<anonymous> (c:\opt\flowfuse-device\project\node_modules\@node-red\editor-api\lib\auth\index.js:64)
handle (c:\opt\flowfuse-device\project\node_modules\express\lib\router\layer.js:95)
next (c:\opt\flowfuse-device\project\node_modules\express\lib\router\route.js:149)
dispatch (c:\opt\flowfuse-device\project\node_modules\express\lib\router\route.js:119)
handle (c:\opt\flowfuse-device\project\node_modules\express\lib\router\layer.js:95)
<anonymous> (c:\opt\flowfuse-device\project\node_modules\express\lib\router\index.js:284)
wrap await got = import('got')
in try...catch
and do a secondary got = require('got')
if necessary.
This allows got to be loaded from device agent node_modules via NODE_PATH
Add explicit entries for got
, http(s)-proxy-agent
& proxy-from-env
to the device project package.json
Careful consideration around existing devices in dev mode or not able to do an npm update, node/node-red versions and other dependencies that may be affected by this change.
I have opted to implement Option 1 in 74ca0dc and this worked (CJS got was loaded) but since implementing this change, i was unable to recreate the original condition (tried switching NR version between 3.x and 4.x streams but the ESM version is always resolved now).
What I didn't capture was actual file system tree of /project/node_module to understand where npm had put things. Looking after the event (as ESM dynamic import
is working, got
is at node_modules/got
- I am unsure if that was the case originally.
Will test again 2x with clean device agent dirs. starting at NR 3.x then upgrading to NR4.x and then in reverse.
@Steve-Mcl Are you still testing this, or does the "TLDR" header mean you've finished poking at it?
Finished (with fingers tightly crossed)
I am still testing locally in case there are any other gotchas of course.
Basic testing working well once I'd configured the proxy to do websockets properly for none secure traffic.
Had a problem with NR 3.1 as the http-request node appears to be doing some strange things (using CONNECT to access http as well as https sites so had to reconfig the proxy to allow this).
NR 3.0.2 has no http_proxy support, so this "broke" when I upgraded the device to 3.1.x might need to look at NR side of things a little. My best guess is that it's using a https proxy agent for everything.
closes #270
Description
no_proxy
andall_proxy
(comes free withproxy-from-env
)*_proxy
env vars through to Node-RED envhttp-proxy-agent
,https-proxy-agent
&proxy-from-env
Notes
http-proxy-agent
&https-proxy-agent
- the most popular and supported agents by a long way, used for both HTTP and MQTT(ws)proxy-from-env
- this determined if a proxy should be applied by inspecting the process env vars. This is the same package thatproxy-agent
uses (proxy-agent
is the parent mono repo ofhttp-proxy-agent
&https-proxy-agent
)eslint-plugin-no-only-tests
proxy
- for testing MQTT comms via a proxyrewire
- used in 2 places.rewire
replacesrequire
and permits access to unreachable internals for unit testingauditLogger/index_spec.js
-auditLogger
only returns a function and was impossible to access internalgot
object for unit testing.template-settings_spec.js
-template-settings
only returns the final settings object and was impossible to access internalgot
object for unit testing.no-only-tests
Tests added
Related Issue(s)
270
Checklist
flowforge.yml
?FlowFuse/helm
to update ConfigMap TemplateFlowFuse/CloudProject
to update values for Staging/ProductionLabels
area:migration
label