diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ed34b9fad..b7239546c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,6 @@ name: PublishDockerImage - +env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true on: release: types: [published] @@ -27,8 +28,6 @@ jobs: with: node-version: '12' - run: node ./node-red/.github/scripts/update-node-red-docker.js - env: - ACTIONS_ALLOW_UNSECURE_COMMANDS: true - name: Create Docker Pull Request uses: peter-evans/create-pull-request@v2 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index c12019755..fdbb4ada9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,25 @@ +### 1.2.7: Maintenance Release + +Editor + + - Ensure subflow-scoped config nodes do not get moved on import Fixes #2789 + - Allow TypedInput to be disabled (#2752) @bartbutenaers + - Allow userMenu to be explicitly enabled (#2805) @tfmf + - Improvements to DE translation (#2192) @ketzu + + +Runtime + + - Handle `undefined` error passed to node.error (#2781) @johnwang71 + - Disable nyc coverage reporting on older node versions + - Improve Editor API unit test coverage (#2777) @aaronmyatt + + +Nodes + + - Trigger: ensure timestamp option sends .now() at point of sending + + ### 1.2.6: Maintenance Release diff --git a/package.json b/package.json index b1981d8cc..cddf1f76e 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ ], "dependencies": { "ajv": "6.12.6", - "async-mutex": "0.2.4", + "async-mutex": "0.2.6", "basic-auth": "2.0.1", "bcryptjs": "2.4.3", "body-parser": "1.19.0", @@ -38,7 +38,7 @@ "cookie-parser": "1.4.5", "cors": "2.8.5", "cron": "1.7.2", - "denque": "1.4.1", + "denque": "1.5.0", "express": "4.17.1", "express-session": "1.17.1", "fs-extra": "8.1.0", @@ -54,11 +54,11 @@ "lodash.clonedeep": "^4.5.0", "media-typer": "1.1.0", "memorystore": "1.6.4", - "mime": "2.4.6", + "mime": "2.4.7", "moment-timezone": "0.5.32", "mqtt": "4.2.6", "multer": "1.4.2", - "mustache": "4.0.1", + "mustache": "4.1.0", "node-red-admin": "^0.2.6", "node-red-node-rbe": "^0.2.9", "node-red-node-sentiment": "^0.1.6", @@ -73,7 +73,7 @@ "request": "2.88.0", "semver": "6.3.0", "tar": "6.0.5", - "uglify-js": "3.11.6", + "uglify-js": "3.12.4", "ws": "6.2.1", "xml2js": "0.4.23" }, @@ -81,7 +81,7 @@ "bcrypt": "3.0.8" }, "devDependencies": { - "dompurify": "2.2.2", + "dompurify": "2.2.6", "grunt": "1.3.0", "grunt-chmod": "~1.1.1", "grunt-cli": "~1.3.2", @@ -103,7 +103,7 @@ "grunt-simple-nyc": "^3.0.1", "http-proxy": "1.18.1", "jsdoc-nr-template": "github:node-red/jsdoc-nr-template", - "marked": "1.2.5", + "marked": "1.2.7", "minami": "1.2.3", "mocha": "^5.2.0", "node-red-node-test-helper": "^0.2.5", diff --git a/packages/node_modules/@node-red/editor-api/package.json b/packages/node_modules/@node-red/editor-api/package.json index 516532e37..0b9ebb224 100644 --- a/packages/node_modules/@node-red/editor-api/package.json +++ b/packages/node_modules/@node-red/editor-api/package.json @@ -25,9 +25,9 @@ "express-session": "1.17.1", "express": "4.17.1", "memorystore": "1.6.4", - "mime": "2.4.6", + "mime": "2.4.7", "multer": "1.4.2", - "mustache": "4.0.1", + "mustache": "4.1.0", "oauth2orize": "1.11.0", "passport-http-bearer": "1.0.1", "passport-oauth2-client-password": "0.1.2", diff --git a/packages/node_modules/@node-red/editor-client/locales/de/editor.json b/packages/node_modules/@node-red/editor-client/locales/de/editor.json index 0c8dd42eb..7c408d742 100755 --- a/packages/node_modules/@node-red/editor-client/locales/de/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/de/editor.json @@ -32,7 +32,7 @@ "label" : { "view" : { "view" : "Ansicht", - "grid" : "Gitter", + "grid" : "Raster", "showGrid" : "Raster anzeigen", "snapGrid" : "Am Raster ausrichten", "gridSize" : "Rastergröße", diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index ddeea65e6..0d664ce3c 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -1360,7 +1360,7 @@ RED.nodes = (function() { } } } else { - if (n.z && !workspaces[n.z]) { + if (n.z && !workspaces[n.z] && !subflow_map[n.z]) { n.z = activeWorkspace; } } diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js index fa1e68cca..332f41fa9 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js @@ -965,6 +965,18 @@ }, hide: function() { this.uiSelect.hide(); + }, + disable: function(val) { + if(val === true) { + this.uiSelect.attr("disabled", "disabled"); + } else if (val === false) { + this.uiSelect.attr("disabled", null); //remove attr + } else { + this.uiSelect.attr("disabled", val); //user value + } + }, + disabled: function() { + return this.uiSelect.attr("disabled"); } }); })(jQuery); diff --git a/packages/node_modules/@node-red/editor-client/src/js/user.js b/packages/node_modules/@node-red/editor-client/src/js/user.js index dd0ff8f90..bd7339285 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/user.js +++ b/packages/node_modules/@node-red/editor-client/src/js/user.js @@ -219,7 +219,7 @@ RED.user = (function() { function init() { if (RED.settings.user) { - if (!RED.settings.editorTheme || !RED.settings.editorTheme.hasOwnProperty("userMenu")) { + if (!RED.settings.editorTheme || !RED.settings.editorTheme.hasOwnProperty("userMenu") || RED.settings.editorTheme.userMenu) { var userMenu = $('
  • ') .prependTo(".red-ui-header-toolbar"); diff --git a/packages/node_modules/@node-red/editor-client/src/sass/ui/common/typedInput.scss b/packages/node_modules/@node-red/editor-client/src/sass/ui/common/typedInput.scss index fb3e331ee..14cb3f70e 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/ui/common/typedInput.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/ui/common/typedInput.scss @@ -26,6 +26,14 @@ box-sizing: border-box; overflow:visible; position: relative; + &[disabled] { + input, button { + background: $secondary-background-inactive; + pointer-events: none; + cursor: not-allowed; + } + } + .red-ui-typedInput-input-wrap { flex-grow: 1; } diff --git a/packages/node_modules/@node-red/nodes/locales/de/messages.json b/packages/node_modules/@node-red/nodes/locales/de/messages.json index 7d9bd3523..fe1e1dfc1 100755 --- a/packages/node_modules/@node-red/nodes/locales/de/messages.json +++ b/packages/node_modules/@node-red/nodes/locales/de/messages.json @@ -583,11 +583,11 @@ "regex" : "Reguläre Ausdrücke verwenden" }, "action" : { - "set" : "Festlegen", + "set" : "Setze", "change" : "Ändern", "delete" : "Löschen", "move" : "Bewegen", - "to" : "bis", + "to" : "auf", "search" : "Suchen nach", "replace" : "Ersetzen durch" }, diff --git a/packages/node_modules/@node-red/nodes/package.json b/packages/node_modules/@node-red/nodes/package.json index 07c107af7..b3e510f9a 100644 --- a/packages/node_modules/@node-red/nodes/package.json +++ b/packages/node_modules/@node-red/nodes/package.json @@ -23,7 +23,7 @@ "cookie": "0.4.1", "cors": "2.8.5", "cron": "1.7.2", - "denque": "1.4.1", + "denque": "1.5.0", "fs-extra": "8.1.0", "fs.notify": "0.0.4", "hash-sum": "2.0.0", @@ -33,7 +33,7 @@ "media-typer": "1.1.0", "mqtt": "4.2.6", "multer": "1.4.2", - "mustache": "4.0.1", + "mustache": "4.1.0", "on-headers": "1.0.2", "raw-body": "2.4.1", "request": "2.88.0", diff --git a/packages/node_modules/@node-red/registry/package.json b/packages/node_modules/@node-red/registry/package.json index 3d517421c..c2c533633 100644 --- a/packages/node_modules/@node-red/registry/package.json +++ b/packages/node_modules/@node-red/registry/package.json @@ -19,6 +19,6 @@ "@node-red/util": "1.3.0-beta.1", "semver": "6.3.0", "tar": "6.0.5", - "uglify-js": "3.11.6" + "uglify-js": "3.12.4" } } diff --git a/packages/node_modules/@node-red/runtime/lib/flows/Flow.js b/packages/node_modules/@node-red/runtime/lib/flows/Flow.js index a4791e084..307da6d62 100644 --- a/packages/node_modules/@node-red/runtime/lib/flows/Flow.js +++ b/packages/node_modules/@node-red/runtime/lib/flows/Flow.js @@ -470,8 +470,8 @@ class Flow { } // console.log("HE",logMessage); var count = 1; - if (msg && msg.hasOwnProperty("error") && msg.error !== null) { - if (msg.error.hasOwnProperty("source") && msg.error.source !== null) { + if (msg && msg.hasOwnProperty("error") && msg.error) { + if (msg.error.hasOwnProperty("source") && msg.error.source) { if (msg.error.source.id === node.id) { count = msg.error.source.count+1; if (count === 10) { diff --git a/packages/node_modules/@node-red/runtime/lib/flows/Subflow.js b/packages/node_modules/@node-red/runtime/lib/flows/Subflow.js index da15ecfe4..87facdc23 100644 --- a/packages/node_modules/@node-red/runtime/lib/flows/Subflow.js +++ b/packages/node_modules/@node-red/runtime/lib/flows/Subflow.js @@ -112,8 +112,8 @@ class Subflow extends Flow { this.node_map = node_map; this.path = parent.path+"/"+(subflowInstance._alias||subflowInstance.id); - this.templateCredentials = credentials.get(subflowDef.id); - this.instanceCredentials = credentials.get(this.id); + this.templateCredentials = credentials.get(subflowDef.id) || {}; + this.instanceCredentials = credentials.get(this.id) || {}; var env = []; if (this.subflowDef.env) { diff --git a/packages/node_modules/@node-red/runtime/package.json b/packages/node_modules/@node-red/runtime/package.json index 1a549e0c6..cd828c50b 100644 --- a/packages/node_modules/@node-red/runtime/package.json +++ b/packages/node_modules/@node-red/runtime/package.json @@ -18,7 +18,7 @@ "dependencies": { "@node-red/registry": "1.3.0-beta.1", "@node-red/util": "1.3.0-beta.1", - "async-mutex": "0.2.4", + "async-mutex": "0.2.6", "clone": "2.1.2", "express": "4.17.1", "fs-extra": "8.1.0", diff --git a/test/unit/@node-red/editor-api/lib/editor/theme_spec.js b/test/unit/@node-red/editor-api/lib/editor/theme_spec.js index 55006f71b..5c8123d61 100644 --- a/test/unit/@node-red/editor-api/lib/editor/theme_spec.js +++ b/test/unit/@node-red/editor-api/lib/editor/theme_spec.js @@ -142,4 +142,19 @@ describe("api/editor/theme", function () { settings.projects.should.have.a.property("enabled", false); }); + it("test explicit userMenu set to true in theme setting", function () { + theme.init({ + editorTheme: { + userMenu: true, + } + }); + + theme.app(); + + var settings = theme.settings(); + settings.should.have.a.property("userMenu"); + settings.userMenu.should.be.eql(true); + + }); + }); diff --git a/test/unit/@node-red/editor-api/lib/index_spec.js b/test/unit/@node-red/editor-api/lib/index_spec.js index ec846cf65..28928181b 100644 --- a/test/unit/@node-red/editor-api/lib/index_spec.js +++ b/test/unit/@node-red/editor-api/lib/index_spec.js @@ -18,10 +18,9 @@ var should = require("should"); var sinon = require("sinon"); var request = require("supertest"); var express = require("express"); -var fs = require("fs"); -var path = require("path"); var NR_TEST_UTILS = require("nr-test-utils"); +const auth = require("basic-auth"); var api = NR_TEST_UTILS.require("@node-red/editor-api"); @@ -95,4 +94,89 @@ describe("api/index", function() { request(api.httpAdmin).get("/auth/login").expect(200).end(done) }) }); + + describe('initialises api with admin middleware', function(done) { + it('ignores non-function values',function(done) { + api.init({ httpAdminRoot: true, httpAdminMiddleware: undefined },{},{},{}); + const middlewareFound = api.httpAdmin._router.stack.filter((layer) => layer.name === 'testMiddleware') + should(middlewareFound).be.empty(); + done(); + }); + + it('only accepts functions as middleware',function(done) { + const testMiddleware = function(req, res, next){ next(); }; + api.init({ httpAdminRoot: true, httpAdminMiddleware: testMiddleware },{},{},{}); + const middlewareFound = api.httpAdmin._router.stack.filter((layer) => layer.name === 'testMiddleware') + should(middlewareFound).be.length(1); + done(); + }); + }); + + describe('initialises api with authentication enabled', function(done) { + + it('enables an oauth/openID based authentication mechanism',function(done) { + const stub = sinon.stub(apiAuth, 'genericStrategy', function(){}); + const adminAuth = { type: 'strategy', strategy: {} } + api.init({ httpAdminRoot: true, adminAuth },{},{},{}); + should(stub.called).be.ok(); + stub.restore(); + done(); + }); + + it('enables password protection',function(done) { + const adminAuth = { type: 'credentials' } + api.init({ httpAdminRoot: true, adminAuth },{},{},{}); + + // is the name ("initialize") of the passport middleware present + const middlewareFound = api.httpAdmin._router.stack.filter((layer) => layer.name === 'initialize') + should(middlewareFound).be.length(1); + done(); + }); + + }); + + describe('initialises api with custom cors config', function (done) { + const httpAdminCors = { + origin: "*", + methods: "GET,PUT,POST,DELETE" + }; + + it('uses default cors middleware when user settings absent', function(done){ + api.init({ httpAdminRoot: true }, {}, {}, {}); + const middlewareFound = api.httpAdmin._router.stack.filter((layer) => layer.name === 'corsMiddleware') + should(middlewareFound).be.length(1); + done(); + }) + + it('enables custom cors middleware when settings present', function(done){ + api.init({ httpAdminRoot: true, httpAdminCors }, {}, {}, {}); + const middlewareFound = api.httpAdmin._router.stack.filter((layer) => layer.name === 'corsMiddleware') + should(middlewareFound).be.length(2); + done(); + }) + }); + + describe('editor start', function (done) { + + it('cannot be started when editor is disabled', function (done) { + const stub = sinon.stub(apiEditor, 'start', function () { + return Promise.resolve(true); + }); + api.init({ httpAdminRoot: true, disableEditor: true }, {}, {}, {}); + should(api.start()).resolvedWith(true); + stub.restore(); + done(); + }); + + it('can be started when editor enabled', function (done) { + const stub = sinon.stub(apiEditor, 'start'); + api.init({ httpAdminRoot: true, disableEditor: false }, {}, {}, {}); + api.start(); + should(stub.called).be.true(); + stub.restore(); + done(); + }); + + }); + });