@gregoriusrippenstein/node-red-contrib-nodedev 0.3.3 → 0.3.5
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/nodes/05-node-dev-ops.html +9 -0
- package/nodes/60-otp-generator.html +124 -0
- package/nodes/60-otp-generator.js +66 -0
- package/nodes/node-factory-sidebar-cfg.html +11 -1
- package/nodes/node-factory-sidebar-cfg.js +47 -0
- package/package.json +4 -2
- package/plugins/node-factory-sidebar.html +293 -43
|
@@ -70,6 +70,8 @@
|
|
|
70
70
|
npmpublish: { value: false },
|
|
71
71
|
npmunpublish: { value: false },
|
|
72
72
|
npmotp: { value: ""},
|
|
73
|
+
|
|
74
|
+
writetgzfile: { value: false },
|
|
73
75
|
},
|
|
74
76
|
|
|
75
77
|
inputs: 0,
|
|
@@ -227,6 +229,13 @@
|
|
|
227
229
|
<input type="checkbox" id="node-input-ignore_package_check" style="display:inline-block; width:15px; vertical-align:baseline;">
|
|
228
230
|
</div>
|
|
229
231
|
|
|
232
|
+
<div class="form-row">
|
|
233
|
+
<label for="node-input-writetgzfile" style="min-width: 150px;"">
|
|
234
|
+
<span>Write .tgz file?</span>
|
|
235
|
+
</label>
|
|
236
|
+
<input type="checkbox" id="node-input-writetgzfile" style="display:inline-block; width:15px; vertical-align:baseline;">
|
|
237
|
+
</div>
|
|
238
|
+
|
|
230
239
|
<hr/>
|
|
231
240
|
|
|
232
241
|
<div class="form-row">
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('OTPGenerate',{
|
|
3
|
+
category: 'nodedev',
|
|
4
|
+
color: '#e5e4ef',
|
|
5
|
+
defaults: {
|
|
6
|
+
name: {value:""},
|
|
7
|
+
|
|
8
|
+
otptype: {value:"totp"},
|
|
9
|
+
secret: { value: "OTP_SECRET"},
|
|
10
|
+
secretType: { value: "env"},
|
|
11
|
+
issuer: { value: "" },
|
|
12
|
+
label: { value: "" },
|
|
13
|
+
digits: { value: 6 },
|
|
14
|
+
period: { value: 30 },
|
|
15
|
+
algorithm: { value: "SHA1" },
|
|
16
|
+
counter: { value: 0 },
|
|
17
|
+
|
|
18
|
+
property: { value:"payload" },
|
|
19
|
+
propertyType: { value:"msg" }
|
|
20
|
+
},
|
|
21
|
+
inputs:1,
|
|
22
|
+
outputs:1,
|
|
23
|
+
icon: "font-awesome/fa-user-secret",
|
|
24
|
+
|
|
25
|
+
label: function() {
|
|
26
|
+
return (this.name || this._def.paletteLabel);
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
labelStyle: function() {
|
|
30
|
+
return this.name?"node_label_italic":"";
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
oneditprepare: function() {
|
|
34
|
+
let that = this;
|
|
35
|
+
|
|
36
|
+
$("#node-input-secret").typedInput({
|
|
37
|
+
types:["env", "msg", "global", "cred"],
|
|
38
|
+
typeField: "#node-input-secretType"
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
$("#node-input-property").typedInput({
|
|
42
|
+
default:'msg',
|
|
43
|
+
types:['msg', 'flow', 'global'],
|
|
44
|
+
typeField: "#node-input-propertyType"
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
$("#node-input-property").typedInput('value', that.property || that._def.defaults.property.value || 'payload');
|
|
48
|
+
$("#node-input-property").typedInput('type', that.propertyType || that._def.defaults.propertyType.value || 'msg');
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<script type="text/html" data-template-name="OTPGenerate">
|
|
54
|
+
<div class="form-row">
|
|
55
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
56
|
+
<input type="text" id="node-input-name" placeholder="Name">
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
<div class="form-row">
|
|
61
|
+
<label for="node-input-otptype"><i class="fa fa-tag"></i> Type</label>
|
|
62
|
+
<select id="node-input-otptype">
|
|
63
|
+
<option value="totp">Time-Based (TOTP)</option>
|
|
64
|
+
<option value="hotp">HMAC-based (HOTP)</option>
|
|
65
|
+
</select>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<div class="form-row" style="margin-left: 10px; margin-top: 20px;">
|
|
69
|
+
<label for="node-input-secret">
|
|
70
|
+
<i class="fa fa-key"></i>
|
|
71
|
+
Secret
|
|
72
|
+
</label>
|
|
73
|
+
<input type="text" id="node-input-secret">
|
|
74
|
+
<input type="hidden" id="node-input-secretType">
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<div class="form-row">
|
|
78
|
+
<label for="node-input-algorithm"><i class="fa fa-tag"></i> Algorithm</label>
|
|
79
|
+
<select id="node-input-algorithm">
|
|
80
|
+
<option value="SHA1">SHA1</option>
|
|
81
|
+
<option value="SHA256">SHA256</option>
|
|
82
|
+
<option value="SHA512">SHA512</option>
|
|
83
|
+
</select>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div class="form-row">
|
|
87
|
+
<label for="node-input-issuer"><i class="fa fa-tag"></i> Issuer</label>
|
|
88
|
+
<input type="text" id="node-input-issuer" placeholder="Issuer">
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<div class="form-row">
|
|
92
|
+
<label for="node-input-label"><i class="fa fa-tag"></i> Label</label>
|
|
93
|
+
<input type="text" id="node-input-label" placeholder="Label">
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<div class="form-row">
|
|
97
|
+
<label for="node-input-digits"><i class="fa fa-tag"></i> Digits</label>
|
|
98
|
+
<input type="text" id="node-input-digits" placeholder="Digits">
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<div class="form-row">
|
|
102
|
+
<label for="node-input-period"><i class="fa fa-tag"></i> Period</label>
|
|
103
|
+
<input type="text" id="node-input-period" placeholder="Period">
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<div class="form-row">
|
|
107
|
+
<label for="node-input-counter"><i class="fa fa-tag"></i> Counter</label>
|
|
108
|
+
<input type="text" id="node-input-counter" placeholder="Counter">
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<hr/>
|
|
112
|
+
|
|
113
|
+
<div class="form-row">
|
|
114
|
+
<label for="node-input-property">Property to set</label>
|
|
115
|
+
<input type="text" id="node-input-property"/>
|
|
116
|
+
<input type="hidden" id="node-input-propertyType"/>
|
|
117
|
+
</div>
|
|
118
|
+
</script>
|
|
119
|
+
|
|
120
|
+
<script type="text/html" data-help-name="OTPGenerate">
|
|
121
|
+
<p>One Time Password (HOTP/TOTP) generator</p>
|
|
122
|
+
|
|
123
|
+
Based off the <a href="https://flows.nodered.org/node/node-red-contrib-otpauth">OTPAuth node</a>
|
|
124
|
+
</script>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const OTPAuth = require('otpauth');
|
|
2
|
+
|
|
3
|
+
module.exports = function (RED) {
|
|
4
|
+
function OTPGeneratorNode(config) {
|
|
5
|
+
RED.nodes.createNode(this, config);
|
|
6
|
+
|
|
7
|
+
let node = this;
|
|
8
|
+
let cfg = config
|
|
9
|
+
|
|
10
|
+
node.on('input', function (msg, send, done) {
|
|
11
|
+
RED.util.evaluateNodeProperty(cfg.secret, cfg.secretType, node, msg, (err, result) => {
|
|
12
|
+
if (err) {
|
|
13
|
+
node.status({ fill: "red", shape: "dot", text: "Failed" });
|
|
14
|
+
node.error("error occurred", { ...msg, _err: err })
|
|
15
|
+
} else {
|
|
16
|
+
let opts = undefined
|
|
17
|
+
|
|
18
|
+
if (typeof msg.payload !== "object") {
|
|
19
|
+
opts = {
|
|
20
|
+
issuer: cfg.issuer,
|
|
21
|
+
label: cfg.label,
|
|
22
|
+
digits: parseInt(cfg.digits),
|
|
23
|
+
secret: msg.payload || result,
|
|
24
|
+
algorithm: cfg.algorithm,
|
|
25
|
+
};
|
|
26
|
+
} else {
|
|
27
|
+
opts = { ...msg.payload }
|
|
28
|
+
|
|
29
|
+
opts.issuer = opts.issuer || cfg.issuer
|
|
30
|
+
opts.label = opts.label || cfg.label
|
|
31
|
+
opts.digits = opts.digits || parseInt(cfg.digits)
|
|
32
|
+
opts.secret = opts.secret || result
|
|
33
|
+
opts.algorithm = opts.algorithm || cfg.algorithm
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let otp = undefined
|
|
37
|
+
|
|
38
|
+
if (cfg.otptype == 'totp') {
|
|
39
|
+
opts.period = parseInt((typeof msg.payload == "object" && msg.payload.period) || cfg.period)
|
|
40
|
+
otp = new OTPAuth.TOTP(opts)
|
|
41
|
+
} else if (cfg.otptype == 'hotp') {
|
|
42
|
+
opts.counter = parseInt((typeof msg.payload == "object" && msg.payload.counter) || cfg.counter)
|
|
43
|
+
otp = new OTPAuth.HOTP(opts)
|
|
44
|
+
} else {
|
|
45
|
+
return node.error("unknown type: " + cfg.otptype, msg)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let otpvalue = otp.generate();
|
|
49
|
+
|
|
50
|
+
if (cfg.propertyType === 'flow' || cfg.propertyType === 'global') {
|
|
51
|
+
node.context()[cfg.propertyType].set(cfg.property, otpvalue, () => {
|
|
52
|
+
send(msg);
|
|
53
|
+
done()
|
|
54
|
+
})
|
|
55
|
+
return;
|
|
56
|
+
} else {
|
|
57
|
+
RED.util.setMessageProperty(msg, cfg.property || 'payload', otpvalue, true);
|
|
58
|
+
send(msg);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
RED.nodes.registerType('OTPGenerate', OTPGeneratorNode);
|
|
66
|
+
}
|
|
@@ -5,7 +5,17 @@
|
|
|
5
5
|
hasUsers: false,
|
|
6
6
|
defaults: {
|
|
7
7
|
pkgname: { value: "node-red-dashboard" },
|
|
8
|
-
pkgversion: { value: "latest" }
|
|
8
|
+
pkgversion: { value: "latest" },
|
|
9
|
+
/* otp stuff */
|
|
10
|
+
otptype: { value: "totp" },
|
|
11
|
+
algorithm: { value: "SHA1"},
|
|
12
|
+
secret: { value: "OTP_SECRET"},
|
|
13
|
+
secretType: { value: "env"},
|
|
14
|
+
issuer: { value: ""},
|
|
15
|
+
otplabel: { value: ""},
|
|
16
|
+
digits: { value: 6 },
|
|
17
|
+
counter: { value: 0 },
|
|
18
|
+
period: { value: 30 }
|
|
9
19
|
},
|
|
10
20
|
paletteLabel: 'PackageImporter',
|
|
11
21
|
label: function () {
|
|
@@ -80,6 +80,53 @@ module.exports = function (RED) {
|
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
RED.httpAdmin.post("/NodeDevOtpGenerator",
|
|
84
|
+
RED.auth.needsPermission("nodedev.write"),
|
|
85
|
+
(req, res) => {
|
|
86
|
+
try {
|
|
87
|
+
if ( req.body ) {
|
|
88
|
+
var msg = req.body;
|
|
89
|
+
var cfgnode = req.body.cfgnode;
|
|
90
|
+
var node = RED.nodes.getNode(cfgnode.id)
|
|
91
|
+
|
|
92
|
+
RED.util.evaluateNodeProperty(cfgnode.secret, cfgnode.secretType, node, msg, (err, result) => {
|
|
93
|
+
if (err || (result || "").trim() == "") {
|
|
94
|
+
res.sendStatus(404);
|
|
95
|
+
} else {
|
|
96
|
+
const OTPAuth = require('otpauth');
|
|
97
|
+
let otp = undefined
|
|
98
|
+
|
|
99
|
+
let opts = {
|
|
100
|
+
issuer: cfgnode.issuer,
|
|
101
|
+
label: cfgnode.otplabel,
|
|
102
|
+
digits: parseInt(cfgnode.digits),
|
|
103
|
+
secret: result,
|
|
104
|
+
algorithm: cfgnode.algorithm,
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
if (cfgnode.otptype == 'totp') {
|
|
108
|
+
opts.period = parseInt(cfgnode.period)
|
|
109
|
+
otp = new OTPAuth.TOTP(opts)
|
|
110
|
+
} else if (cfg.otptype == 'hotp') {
|
|
111
|
+
opts.counter = parseInt(cfgnode.counter)
|
|
112
|
+
otp = new OTPAuth.HOTP(opts)
|
|
113
|
+
} else {
|
|
114
|
+
return res.send("unknown otp type").status(404)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
res.send({data:{otp:otp.generate()}}).status(200)
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
} else {
|
|
121
|
+
res.sendStatus(406);
|
|
122
|
+
}
|
|
123
|
+
} catch (ex) {
|
|
124
|
+
console.error("ERROR", ex)
|
|
125
|
+
res.sendStatus(500);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
|
|
83
130
|
RED.httpAdmin.post("/NodeFactorySidebarCfg",
|
|
84
131
|
RED.auth.needsPermission("nodedev.write"),
|
|
85
132
|
(req, res) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name" : "@gregoriusrippenstein/node-red-contrib-nodedev",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"pako": "^2.1.0",
|
|
6
6
|
"tar-stream": "^3.1.6",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"libnpmpublish": "^9.0.0",
|
|
9
9
|
"streamx": "^2.15.5",
|
|
10
10
|
"got": "^13",
|
|
11
|
-
"pacote": "^17.0.4"
|
|
11
|
+
"pacote": "^17.0.4",
|
|
12
|
+
"otpauth": "^5.0.8"
|
|
12
13
|
},
|
|
13
14
|
|
|
14
15
|
"keywords": [
|
|
@@ -38,6 +39,7 @@
|
|
|
38
39
|
"npmtarball": "nodes/30-npm-tarball.js",
|
|
39
40
|
"noderedinstall": "nodes/40-node-red-install.js",
|
|
40
41
|
"npmpublish": "nodes/50-npm-publish.js",
|
|
42
|
+
"otpgenerator": "nodes/60-otp-generator.js",
|
|
41
43
|
"nodefactorycfg": "nodes/node-factory-sidebar-cfg.js"
|
|
42
44
|
}
|
|
43
45
|
},
|
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
(function() {
|
|
3
3
|
var globalYourConfigNode = null;
|
|
4
4
|
|
|
5
|
+
function doGenerateOTP(cfgnode, cb) {
|
|
6
|
+
ensureYourConfigNodeExists();
|
|
7
|
+
|
|
8
|
+
$.ajax({
|
|
9
|
+
url: "NodeDevOtpGenerator",
|
|
10
|
+
type: "POST",
|
|
11
|
+
contentType: "application/json; charset=utf-8",
|
|
12
|
+
|
|
13
|
+
data: JSON.stringify({
|
|
14
|
+
cfgnode: cfgnode
|
|
15
|
+
}),
|
|
16
|
+
|
|
17
|
+
success: function (resp) {
|
|
18
|
+
$('#node-input-nodedev-sidebar-otp').val(resp.data.otp)
|
|
19
|
+
cb(resp)
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
error: function (jqXHR, textStatus, errorThrown) {
|
|
23
|
+
RED.notify("Generating failed: " + textStatus, {
|
|
24
|
+
type: "error",
|
|
25
|
+
id: "NodeFactorySidebar",
|
|
26
|
+
timeout: 2000
|
|
27
|
+
});
|
|
28
|
+
console.log(textStatus,errorThrown )
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
5
34
|
function doSubmission(pkgname,pkgversion) {
|
|
6
35
|
ensureYourConfigNodeExists();
|
|
7
36
|
|
|
@@ -73,16 +102,25 @@
|
|
|
73
102
|
let typ = RED.nodes.getType("NodeFactorySidebarCfg");
|
|
74
103
|
|
|
75
104
|
globalYourConfigNode = {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
105
|
+
id: RED.nodes.id(), // on the server side, this is called RED.util.generateId()
|
|
106
|
+
_def: typ,
|
|
107
|
+
type: "NodeFactorySidebarCfg",
|
|
108
|
+
hasUsers: false,
|
|
109
|
+
users: [],
|
|
110
|
+
name: "NodeFactorySidebar",
|
|
111
|
+
label: function() { return this.name || "NodeFactorySidebar"},
|
|
112
|
+
/* values and data defined by this config node */
|
|
113
|
+
pkgname: typ.defaults.pkgname.value,
|
|
114
|
+
pkgversion: typ.defaults.pkgversion.value,
|
|
115
|
+
otptype: typ.defaults.otptype.value,
|
|
116
|
+
algorithm: typ.defaults.algorithm.value,
|
|
117
|
+
secret: typ.defaults.secret.value,
|
|
118
|
+
secretType: typ.defaults.secretType.value,
|
|
119
|
+
issuer: typ.defaults.issuer.value,
|
|
120
|
+
otplabel: typ.defaults.otplabel.value,
|
|
121
|
+
digits: typ.defaults.digits.value,
|
|
122
|
+
counter: typ.defaults.counter.value,
|
|
123
|
+
period: typ.defaults.period.value
|
|
86
124
|
}
|
|
87
125
|
|
|
88
126
|
// Add the new config node to the collection of Node-RED nodes
|
|
@@ -104,8 +142,8 @@
|
|
|
104
142
|
// --> more details: https://nodered.org/docs/api/ui/sidebar/
|
|
105
143
|
RED.sidebar.addTab({
|
|
106
144
|
id: "NodeFactorySidebar",
|
|
107
|
-
label: "
|
|
108
|
-
name: "
|
|
145
|
+
label: "Node Dev", // short name for the tab
|
|
146
|
+
name: "Node Dev", // long name for the menu
|
|
109
147
|
content: content,
|
|
110
148
|
closeable: true,
|
|
111
149
|
// disableOnEdit: true,
|
|
@@ -113,8 +151,34 @@
|
|
|
113
151
|
iconClass: "fa fa-industry" // your fontawesome icon
|
|
114
152
|
});
|
|
115
153
|
|
|
154
|
+
var tabs = RED.tabs.create({
|
|
155
|
+
id: 'func-nodedev-pkgimporter-tabs',
|
|
156
|
+
onchange: function(tab) {
|
|
157
|
+
$('#func-nodedev-pkgimporter-tabs-content').children().hide();
|
|
158
|
+
$('#' + tab.id).show();
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Add first tab, pkg importer
|
|
163
|
+
tabs.addTab({
|
|
164
|
+
id: 'func-nodedev-pkgimporter-tab-pkgimport',
|
|
165
|
+
iconClass: 'fa fa-industry',
|
|
166
|
+
label: 'PkgImporter'
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Add first tab, otp
|
|
170
|
+
tabs.addTab({
|
|
171
|
+
id: 'func-nodedev-pkgimporter-tab-otpgenerator',
|
|
172
|
+
iconClass: 'fa fa-user-secret',
|
|
173
|
+
label: 'OTP Generator'
|
|
174
|
+
});
|
|
175
|
+
|
|
116
176
|
ensureYourConfigNodeExists();
|
|
117
177
|
|
|
178
|
+
/*
|
|
179
|
+
************ Package importer handlers
|
|
180
|
+
*/
|
|
181
|
+
|
|
118
182
|
var doSomething = (e) => {
|
|
119
183
|
if (e) { e.preventDefault(); }
|
|
120
184
|
doSubmission()
|
|
@@ -145,6 +209,123 @@
|
|
|
145
209
|
}
|
|
146
210
|
})
|
|
147
211
|
$("#node-input-nodefactorysidebar-package-name").val(globalYourConfigNode.pkgname);
|
|
212
|
+
|
|
213
|
+
/*
|
|
214
|
+
************* OTP generator handlers
|
|
215
|
+
*/
|
|
216
|
+
|
|
217
|
+
$("#node-input-nodedev-sidebar-otp-secret").typedInput({
|
|
218
|
+
types:["env", "msg", "global", "cred"],
|
|
219
|
+
typeField: "#node-input-nodedev-sidebar-otp-secretType"
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
$("#node-input-nodedev-sidebar-otp-secret").typedInput( 'value', globalYourConfigNode.secret || globalYourConfigNode._def.defaults.secret.value );
|
|
223
|
+
$("#node-input-nodedev-sidebar-otp-secret").typedInput( 'type', globalYourConfigNode.secretType || globalYourConfigNode._def.defaults.secretType.value);
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
$("#node-input-nodedev-sidebar-otp-secret").on('change', () => {
|
|
227
|
+
ensureYourConfigNodeExists();
|
|
228
|
+
|
|
229
|
+
let val = $("#node-input-nodedev-sidebar-otp-secret").typedInput('value');
|
|
230
|
+
let typ = $("#node-input-nodedev-sidebar-otp-secret").typedInput('type');
|
|
231
|
+
|
|
232
|
+
if ( val != globalYourConfigNode.secret ) {
|
|
233
|
+
globalYourConfigNode.secret = val;
|
|
234
|
+
RED.nodes.dirty(true);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if ( typ != globalYourConfigNode.secretType ) {
|
|
238
|
+
globalYourConfigNode.secretType = typ;
|
|
239
|
+
RED.nodes.dirty(true);
|
|
240
|
+
}
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
$('#node-input-nodedev-sidebar-otp-otptype').val(globalYourConfigNode.otptype || globalYourConfigNode._def.defaults.otptype.value)
|
|
244
|
+
$('#node-input-nodedev-sidebar-otp-algorithm').val(globalYourConfigNode.algorithm || globalYourConfigNode._def.defaults.algorithm.value)
|
|
245
|
+
$('#node-input-nodedev-sidebar-otp-issuer').val(globalYourConfigNode.issuer || globalYourConfigNode._def.defaults.issuer.value)
|
|
246
|
+
$('#node-input-nodedev-sidebar-otp-label').val(globalYourConfigNode.otplabel || globalYourConfigNode._def.defaults.otplabel.value)
|
|
247
|
+
$('#node-input-nodedev-sidebar-otp-digits').val(globalYourConfigNode.digits || globalYourConfigNode._def.defaults.digits.value)
|
|
248
|
+
$('#node-input-nodedev-sidebar-otp-period').val(globalYourConfigNode.period || globalYourConfigNode._def.defaults.period.value)
|
|
249
|
+
$('#node-input-nodedev-sidebar-otp-counter').val(globalYourConfigNode.counter || globalYourConfigNode._def.defaults.counter.value)
|
|
250
|
+
|
|
251
|
+
$('#node-input-nodedev-sidebar-otp-otptype').on('change', () => {
|
|
252
|
+
ensureYourConfigNodeExists();
|
|
253
|
+
let val = $('#node-input-nodedev-sidebar-otp-otptype').val()
|
|
254
|
+
|
|
255
|
+
if ( val != globalYourConfigNode.otptype) {
|
|
256
|
+
globalYourConfigNode.otptype = val
|
|
257
|
+
RED.nodes.dirty(true);
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
$('#node-input-nodedev-sidebar-otp-algorithm').on('change', () => {
|
|
262
|
+
ensureYourConfigNodeExists();
|
|
263
|
+
let val = $('#node-input-nodedev-sidebar-otp-algorithm').val()
|
|
264
|
+
|
|
265
|
+
if ( val != globalYourConfigNode.algorithm) {
|
|
266
|
+
globalYourConfigNode.algorithm = val
|
|
267
|
+
RED.nodes.dirty(true);
|
|
268
|
+
}
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
$('#node-input-nodedev-sidebar-otp-issuer').on('change', () => {
|
|
272
|
+
ensureYourConfigNodeExists();
|
|
273
|
+
let val = $('#node-input-nodedev-sidebar-otp-issuer').val()
|
|
274
|
+
|
|
275
|
+
if ( val != globalYourConfigNode.issuer) {
|
|
276
|
+
globalYourConfigNode.issuer = val
|
|
277
|
+
RED.nodes.dirty(true);
|
|
278
|
+
}
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
$('#node-input-nodedev-sidebar-otp-label').on('change', () => {
|
|
282
|
+
ensureYourConfigNodeExists();
|
|
283
|
+
let val = $('#node-input-nodedev-sidebar-otp-label').val()
|
|
284
|
+
|
|
285
|
+
if ( val != globalYourConfigNode.otplabel) {
|
|
286
|
+
globalYourConfigNode.otplabel = val
|
|
287
|
+
RED.nodes.dirty(true);
|
|
288
|
+
}
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
$('#node-input-nodedev-sidebar-otp-digits').on('change', () => {
|
|
292
|
+
ensureYourConfigNodeExists();
|
|
293
|
+
let val = $('#node-input-nodedev-sidebar-otp-digits').val()
|
|
294
|
+
|
|
295
|
+
if ( val != globalYourConfigNode.digits) {
|
|
296
|
+
globalYourConfigNode.digits = val
|
|
297
|
+
RED.nodes.dirty(true);
|
|
298
|
+
}
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
$('#node-input-nodedev-sidebar-otp-period').on('change', () => {
|
|
302
|
+
ensureYourConfigNodeExists();
|
|
303
|
+
let val = $('#node-input-nodedev-sidebar-otp-period').val()
|
|
304
|
+
|
|
305
|
+
if ( val != globalYourConfigNode.period) {
|
|
306
|
+
globalYourConfigNode.period = val
|
|
307
|
+
RED.nodes.dirty(true);
|
|
308
|
+
}
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
$('#node-input-nodedev-sidebar-otp-counter').on('change', () => {
|
|
312
|
+
ensureYourConfigNodeExists();
|
|
313
|
+
let val = $('#node-input-nodedev-sidebar-otp-counter').val()
|
|
314
|
+
|
|
315
|
+
if ( val != globalYourConfigNode.counter) {
|
|
316
|
+
globalYourConfigNode.counter = val
|
|
317
|
+
RED.nodes.dirty(true);
|
|
318
|
+
}
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
$('#nodedev-sidebar-otp-generate-btn').on('click', e => {
|
|
322
|
+
if ( e) { e.preventDefault()}
|
|
323
|
+
ensureYourConfigNodeExists();
|
|
324
|
+
|
|
325
|
+
doGenerateOTP(globalYourConfigNode, (resp) => {
|
|
326
|
+
$('#node-input-nodedev-sidebar-otp').val(resp.data.otp)
|
|
327
|
+
})
|
|
328
|
+
})
|
|
148
329
|
};
|
|
149
330
|
|
|
150
331
|
RED.events.on('runtime-state', initialiseConfigNodeOnce);
|
|
@@ -153,40 +334,109 @@
|
|
|
153
334
|
|
|
154
335
|
<!-- The html for the right sidebar plugin screen -->
|
|
155
336
|
<script type="text/x-red" data-template-name="NodeFactorySidebar">
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
337
|
+
<div class="form-row func-nodedev-pkgimporter-tabs-row">
|
|
338
|
+
<ul style="min-width: 600px; margin-bottom: 20px;" id="func-nodedev-pkgimporter-tabs"></ul>
|
|
339
|
+
</div>
|
|
340
|
+
|
|
341
|
+
<div id="func-nodedev-pkgimporter-tabs-content" style="min-height: calc(100% - 95px);">
|
|
342
|
+
|
|
343
|
+
<div id="func-nodedev-pkgimporter-tab-pkgimport" style="display:none">
|
|
344
|
+
|
|
345
|
+
<div class="form-row" style="margin-left: 10px; margin-top: 30px;">
|
|
346
|
+
Import <a href="https://npmjs.com" target=_blank>npmJs.com</a> packages as a flow. packages
|
|
347
|
+
are imported as a collection of PkgFile nodes. This can help to learn from other
|
|
348
|
+
peoples experiences and code.
|
|
349
|
+
</div>
|
|
350
|
+
|
|
351
|
+
<div class="form-row" style="margin-left: 10px;">
|
|
352
|
+
Enter package details here:
|
|
353
|
+
</div>
|
|
354
|
+
|
|
355
|
+
<div class="form-row" style="margin-left: 10px;">
|
|
356
|
+
<label for="node-input-nodefactorysidebar-package-name">
|
|
357
|
+
<i class="fa fa-tag"></i>
|
|
358
|
+
Name
|
|
359
|
+
</label>
|
|
360
|
+
<input type="text" id="node-input-nodefactorysidebar-package-name"
|
|
172
361
|
placeholder="node-red-dashboard">
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
362
|
+
</div>
|
|
363
|
+
|
|
364
|
+
<div class="form-row" style="margin-left: 10px;">
|
|
365
|
+
<label for="node-input-nodefactorysidebar-package-version">
|
|
366
|
+
<i class="fa fa-tag"></i>
|
|
367
|
+
Version
|
|
368
|
+
</label>
|
|
369
|
+
<input type="text" id="node-input-nodefactorysidebar-package-version"
|
|
181
370
|
placeholder="3.5.0">
|
|
182
|
-
|
|
371
|
+
</div>
|
|
183
372
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
373
|
+
<div class="form-row">
|
|
374
|
+
<div style="position: relative; height: 100%; margin: 15px;">
|
|
375
|
+
<button id="node-input-nodefactorysidebar-generate-btn"
|
|
187
376
|
class="red-ui-button"
|
|
188
377
|
style="width: 100%; margin-top: 30px">Import Package</button>
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
378
|
+
</div>
|
|
379
|
+
</div>
|
|
380
|
+
|
|
381
|
+
</div>
|
|
382
|
+
|
|
383
|
+
<div id="func-nodedev-pkgimporter-tab-otpgenerator" style="display:none">
|
|
384
|
+
|
|
385
|
+
<div class="form-row" style="margin-left: 10px;">
|
|
386
|
+
<label for="node-input-nodedev-sidebar-otp-otptype"><i class="fa fa-tag"></i> Type</label>
|
|
387
|
+
<select id="node-input-nodedev-sidebar-otp-otptype">
|
|
388
|
+
<option value="totp">Time-Based (TOTP)</option>
|
|
389
|
+
<option value="hotp">HMAC-based (HOTP)</option>
|
|
390
|
+
</select>
|
|
391
|
+
</div>
|
|
392
|
+
|
|
393
|
+
<div class="form-row" style="margin-left: 10px;">
|
|
394
|
+
<label for="node-input-nodedev-sidebar-otp-secret">
|
|
395
|
+
<i class="fa fa-key"></i>
|
|
396
|
+
Secret
|
|
397
|
+
</label>
|
|
398
|
+
<input type="text" id="node-input-nodedev-sidebar-otp-secret">
|
|
399
|
+
<input type="hidden" id="node-input-nodedev-sidebar-otp-secretType">
|
|
400
|
+
</div>
|
|
401
|
+
|
|
402
|
+
<div class="form-row" style="margin-left: 10px;">
|
|
403
|
+
<label for="node-input-nodedev-sidebar-otp-algorithm"><i class="fa fa-tag"></i> Algorithm</label>
|
|
404
|
+
<select id="node-input-nodedev-sidebar-otp-algorithm">
|
|
405
|
+
<option value="SHA1">SHA1</option>
|
|
406
|
+
<option value="SHA256">SHA256</option>
|
|
407
|
+
<option value="SHA512">SHA512</option>
|
|
408
|
+
</select>
|
|
409
|
+
</div>
|
|
410
|
+
|
|
411
|
+
<div class="form-row" style="margin-left: 10px;">
|
|
412
|
+
<label for="node-input-nodedev-sidebar-otp-issuer"><i class="fa fa-tag"></i> Issuer</label>
|
|
413
|
+
<input type="text" id="node-input-nodedev-sidebar-otp-issuer" placeholder="Issuer">
|
|
414
|
+
</div>
|
|
415
|
+
|
|
416
|
+
<div class="form-row" style="margin-left: 10px;">
|
|
417
|
+
<label for="node-input-nodedev-sidebar-otp-label"><i class="fa fa-tag"></i> Label</label>
|
|
418
|
+
<input type="text" id="node-input-nodedev-sidebar-otp-label" placeholder="Label">
|
|
419
|
+
</div>
|
|
420
|
+
|
|
421
|
+
<div class="form-row" style="margin-left: 10px;">
|
|
422
|
+
<label for="node-input-nodedev-sidebar-otp-digits"><i class="fa fa-tag"></i> Digits</label>
|
|
423
|
+
<input type="text" id="node-input-nodedev-sidebar-otp-digits" placeholder="Digits">
|
|
424
|
+
</div>
|
|
425
|
+
|
|
426
|
+
<div class="form-row" style="margin-left: 10px;">
|
|
427
|
+
<label for="node-input-nodedev-sidebar-otp-period"><i class="fa fa-tag"></i> Period</label>
|
|
428
|
+
<input type="text" id="node-input-nodedev-sidebar-otp-period" placeholder="Period">
|
|
429
|
+
</div>
|
|
430
|
+
|
|
431
|
+
<div class="form-row" style="margin-left: 10px;">
|
|
432
|
+
<label for="node-input-nodedev-sidebar-otp-counter"><i class="fa fa-tag"></i> Counter</label>
|
|
433
|
+
<input type="text" id="node-input-nodedev-sidebar-otp-counter" placeholder="Counter">
|
|
434
|
+
</div>
|
|
435
|
+
|
|
436
|
+
<div class="form-row" style="margin-left: 10px;">
|
|
437
|
+
<button id="nodedev-sidebar-otp-generate-btn" class="button">Generate</button>
|
|
438
|
+
<input type="text" id="node-input-nodedev-sidebar-otp" placeholder="OTP...">
|
|
439
|
+
</div>
|
|
440
|
+
</div>
|
|
441
|
+
</div>
|
|
192
442
|
</script>
|