๐ŸŒ UIBUILDER new release v7.6.1: (Bug fix) Introducing Markweb and other enhancements

OK, just back from a quick visit to the Sheffield Botanical Gardens. Turns out there are still plenty of Bluebells still on offer there. :slight_smile:


Down south, ours are nearly over. This was two weeks ago

Also "down south" Bluebells in the churchyard of my local village church yesterday...


This was last year, and even with the fine weather it was May before this happened, not even a blue tinge yet. (Just opposite our house)

Sorry, moved to another topic as I'm getting lost in this one. :smiley:

My question relates to your CSP instructions above. I am getting CSP Errors trying to embed a Grafana Graph into a Webpage, I assume that I need to add my source http to the CSP, but I can only find uibMiddleware.js-template in the ~/.node-red/projects/<project>/uibuilder/.config directory. Is this the correct file? Do I need to save it to the /.common directory?

To save coming back, again, I assume that I would need to add something like
"connect-src 'self' http:<IP_ADDRESS:3000>; "

TIA

Yes, I recommend making a copy, just change the end of the name from .js-template to .js.

Apologies that the CSP stuff is causing confusion. I'm wondering if I should have made that change. However, it does strengthen security of your pages quite a lot.

Thankfully, if you check your browser's console, it gives a hint about what you need to change.

Yes, that should work. I think that "connect-src 'self' http:<IP_ADDRESS>; " might also work if you want to allow embedding of any iframe from that server.

For reference, if connecting to things over the internet, folk should ensure they only ever add https sources and never http. But it is OK for your own local resources (as long as your local network is reasonably secure anyway :wink: ).

PS: At some point, I'll add an easier way by letting you add the middleware in settings.js. Or possibly without the middleware function at all, using a configuration object. We will see.

Hi Julian

I original error was this....

Content-Security-Policy: The pageโ€™s settings blocked the loading of a resource (frame-src) at http://<IP_ADDRESS>/d-solo/e166e701-3a30-412b-b153-8f84e1ee02e4/electricity-costs?orgId=1&refresh=30s&from=now-24h&to=now%2B32h&panelId=1 because it violates the following directive: โ€œdefault-src 'self' 'unsafe-inline' data: blob: https:โ€

So, I copied your example and still got the same message. Not to be beaten, I fiddled around with the order and put the Grafana Server IP first.

function uibMw(req, res, next) {
console.log('[uibuilder:uibMiddleware.js] Custom ExpressJS middleware called.')
res.setHeader('X-Custom-JK-Header', 'This is a custom header set by uibMiddleware.js')

// Define your policy string
let csp =
"default-src 'self' http://<IP_ADDRESS>; "
+ "connect-src 'self' 'unsafe-inline' data: blob: https:; "

I then tried the Nuclear option
let csp = '*' and got the exact message above - it is actually the error I copied, but the error was the same for all.

Is .config the correct directory for this file, or is something else overriding UIBUILDER CSP?

Thank you,
Colin

I have to add, this link works in Dashboard 1.

So, firstly check whether you are getting the log output from the custom middleware function in your Node-RED log. You could also check your browser network tab to see if you are getting the extra custom header.

After that, here are the clues:

default-src

Tells you that the CSP is falling back to using the default rather than the more explicit frame-src.

So you should add a frame-src 'self' http://<IP_ADDRESS>;

Nothing in the NR log other than suncalc complaining it is too soon to update!

All I can see here is the GET command... Using Vivaldi I see this in the Network Tab

This is how my csp looks now - just this rule.

// Define your policy string
let csp =
"frame-src 'self' http://<IP_ADDRESS>; "

Interesting...

BTW NR was restarted after every edit.

No, that won't work at all I'm afraid! You need all the other stuff as well. What you've specified is that your browser won't accept ANY dynamic data at all, not even local - other than allowing an iframe.

Here is what I think you need in <uibRoot>/.config/uibMiddleware.js:

/**
 * Template ExpressJS Middleware for uibuilder.
 * UPDATED: 2022-04-01
 *
 * NOTES & WARNINGS:
 *   1) This function is called EVERY TIME any web call is made to the URL defined by your uib instance.
 *      So it should be kept short and efficient.
 *   2) Failing to either return or call `next()` will cause an ExpressJS error.
 *   3) An error in this function will probably cause Node-RED to fail to start at all.
 *   4) You have to restart Node-RED if you change this file.
 *   5) To use for authentication/authorisation with sio connection middleware, create a common node.js module.
 *
 * Allows custom processing for authentication, session management, custom logging, etc.
 * 
 * @param {object} req The ExpressJS request object
 * @param {object} res The ExpressJS result object
 * @param {function} next The callback to hand off to the next middleware
 */
function uibMw(req, res, next) {

    console.log('[uibuilder:uibMiddleware.js] Custom ExpressJS middleware called.')
    res.setHeader('X-Custom-JK-Header', 'This is a custom header set by uibMiddleware.js')

    // Define your policy string
    let csp =
        "default-src 'self' 'unsafe-inline' data: blob: https:; "
        + "connect-src 'self' ws: wss:; "
        + "img-src 'self' data: blob: https: https://cdn.jsdelivr.net; "
        + "font-src 'self' data: https:; "
        + "style-src 'self' 'unsafe-inline' data: blob: https:; "
        + "script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: https:; "
        + "frame-src 'self' http:; " // add the ipaddress if you want to be more secure (definitely if you ever expose over the Internet
    // csp = '*' // Disable CSP - not recommended for production but can be useful for development and testing
    // Set the header
    res.setHeader('Content-Security-Policy', csp)
    
    next()

} // Do not forget to end with a call to `next()`

module.exports = uibMw

Got it!

Thank you Julian, have a good evening.!

Not sure about that - you've sent me down a new rabbit hole in the uibuilder code!

I noticed that, because uib, in recent releases, has a runtime plugin. And since these get loaded first. And because we now have Markweb that is effectively a simplified uibuilder node with some smart extra's. It makes sense to move some of the uibuilder setup code into the plugin. Making it available to all uibuilder package nodes.

So, v7.7 (which might become v8.0 depending on the timing of the Node-RED v5 release) was already well under way - with Mermaid and Footnotes already added to Markweb and a bunch of edge-cases dealt with. And now it gets some TLC around startup. :smiley:

Ahhh... Sorry about that, but you know that you enjoy a challenge!!

But then again, I might be able to at least make a small claim that I am part responsible for a step change in the way UIBUILDER works. And, I do have to say, that I really do enjoy standing on someone elses coat tails!!:rofl:

Seriously, I am glad that I have triggered some of your neurons to develop UIBUILDER further. And every day is a learning day, what would Retirement be without challenges.

Sorry for the late reply, visiting a daughter this weekend, was traveling yesterday. I do appreciate your work and help!

Thank you Julian.

Yep! And for sure, you have been a positive agent of change for UIBUILDER. :smiley:

A motto to live by. :wink:

Darn that "real life", getting in the way. :rofl:


Anyway, v7.7 (or 8) has some positive, if behind-the-scenes changes.

You may be glad to here that there is an easier way to override the CSP values using settings.js rather than having to mess with a middleware file. And in Markdown, Mermaid diagrams and Footnotes are now possible.

You just want me to use the Markweb Module, don't you! I thought I was going to get away with that!!:rofl:

Keep up the Good Work!

Thanks.

Not all about Markweb, though I am very pleased with that outcome.

Just to whet your appetite further, another new component (AKA Widget) being made available for the next release:

A nice JavaScript Object and JSON display widget. Complete with filtering, collapsible and even editable. The important thing being that it copes with complex JS Objects as you can see. There is also a converter exposed to function nodes in case you just want a quick way to convert some Node-RED data to HTML.