@vitormnm/node-red-simple-opcua 1.6.3 → 1.7.0

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 (42) hide show
  1. package/README.md +89 -136
  2. package/client/lib/opcua-client-browser.js +238 -10
  3. package/client/lib/opcua-client-method-service.js +1 -1
  4. package/client/lib/opcua-client-subscription-service.js +0 -2
  5. package/client/opcua-client-config.html +118 -1
  6. package/client/opcua-client-config.js +74 -8
  7. package/client/opcua-client-help.html +6 -0
  8. package/client/opcua-client-utils.js +34 -10
  9. package/client/opcua-client.html +7 -0
  10. package/client/opcua-client.js +97 -1
  11. package/examples/flows_simple_opc.json +1 -1
  12. package/package.json +1 -1
  13. package/server/lib/opcua-address-space-alarm.js +11 -5
  14. package/server/lib/opcua-address-space-builder.js +65 -15
  15. package/server/lib/opcua-config.js +81 -23
  16. package/server/lib/opcua-server-events-child.js +1 -1
  17. package/server/lib/opcua-server-runtime-child.js +284 -19
  18. package/server/lib/opcua-server-runtime.js +49 -5
  19. package/server/lib/opcua-server-status-child.js +14 -14
  20. package/server/nodered/simple_opcua/server/certificates/mutex +0 -0
  21. package/server/nodered/simple_opcua/server/certificates/own/certs/server_selfsigned_cert_2048.pem +25 -0
  22. package/server/nodered/simple_opcua/server/certificates/own/certs/server_selfsigned_cert_2048.pem.mutex +0 -0
  23. package/server/nodered/simple_opcua/server/certificates/own/openssl.cnf +72 -0
  24. package/server/nodered/simple_opcua/server/certificates/own/private/private_key.pem +28 -0
  25. package/server/nodered/simple_opcua/server/certificates/trusted/certs/NodeOPCUA-Client@tuf[c5a9e20a8b680cdff76aaf0165bb3c9318da37a5].pem +25 -0
  26. package/server/nodered/simple_opcua/server/myServer1/mutex +0 -0
  27. package/server/nodered/simple_opcua/server/myServer1/own/certs/server_selfsigned_cert_2048.pem +25 -0
  28. package/server/nodered/simple_opcua/server/myServer1/own/certs/server_selfsigned_cert_2048.pem.mutex +0 -0
  29. package/server/nodered/simple_opcua/server/myServer1/own/openssl.cnf +72 -0
  30. package/server/nodered/simple_opcua/server/myServer1/own/private/private_key.pem +28 -0
  31. package/server/nodered/simple_opcua/server/myServer1/trusted/certs/NodeOPCUA-Client@tuf[91e520c64ff891c67168f08a46dd194071e15dae].pem +25 -0
  32. package/server/nodered/simple_opcua/server/myServer1/trusted/certs/NodeOPCUA-Client@tuf[98ae95da627cea4c500753c319161a3554ee38d7].pem +25 -0
  33. package/server/nodered/simple_opcua/server/myServer1/trusted/certs/NodeOPCUA-Client@tuf[aef8d7a1cfba13d84189a0bcf1694208fc51a7f9].pem +25 -0
  34. package/server/nodered/simple_opcua/server/myServer1/trusted/certs/NodeOPCUA-Client@tuf[c5a9e20a8b680cdff76aaf0165bb3c9318da37a5].pem +25 -0
  35. package/server/nodered/simple_opcua/server/myServer1/trusted/certs/NodeOPCUA-Client@tuf[ebdf9acf1d02e347917a14108d3144799c638ea3].pem +25 -0
  36. package/server/opcua-server-io.html +76 -0
  37. package/server/opcua-server-io.js +130 -27
  38. package/server/opcua-server.css +52 -0
  39. package/server/opcua-server.html +166 -44
  40. package/server/opcua-server.js +115 -5
  41. package/server/view/opcua-server.css +89 -6
  42. package/server/view/opcua-server.js +523 -42
@@ -257,18 +257,33 @@ class OpcUaServerProcess {
257
257
 
258
258
 
259
259
 
260
- process.send({
261
- type: "send",
262
- data: msg,
263
- nodeId: nodeId
264
- });
260
+ let hasFailures = false;
261
+ if (readArrayResults) {
262
+ const failed = readArrayResults.filter(item => item && item.status !== "Good");
263
+ if (failed.length) {
264
+ hasFailures = true;
265
+ }
266
+ }
267
+ if (result.directError) {
268
+ hasFailures = true;
269
+ }
270
+
271
+ if (!hasFailures) {
272
+ process.send({
273
+ type: "send",
274
+ data: msg,
275
+ nodeId: nodeId
276
+ });
277
+ }
265
278
 
266
279
  process.send({
267
280
  type: "status",
268
281
  data: {
269
- fill: "green",
282
+ fill: hasFailures ? (result.directError ? "red" : "yellow") : "green",
270
283
  shape: "dot",
271
- text: result.identifiers.length > 1 ? "read " + result.identifiers.length + " tags" : "read " + result.identifiers[0]
284
+ text: hasFailures
285
+ ? (result.directError ? "read failed" : "partial read failed")
286
+ : (result.identifiers.length > 1 ? "read " + result.identifiers.length + " tags" : "read " + result.identifiers[0])
272
287
  },
273
288
  nodeId: nodeId
274
289
  });
@@ -308,6 +323,7 @@ class OpcUaServerProcess {
308
323
  type: "error",
309
324
  data: { fill: "red", shape: "ring", text: "failed read" },
310
325
  error: error.message,
326
+ originalMsg: msg,
311
327
  nodeId: nodeId
312
328
  });
313
329
  }
@@ -362,6 +378,7 @@ class OpcUaServerProcess {
362
378
  type: "error",
363
379
  data: { fill: "red", shape: "ring", text: "failed write" },
364
380
  error: error.message,
381
+ originalMsg: msg,
365
382
  nodeId: nodeId
366
383
  });
367
384
  }
@@ -524,21 +541,33 @@ class OpcUaServerProcess {
524
541
  msg.topic = writtenPaths[0];
525
542
  }
526
543
 
527
- process.send({
528
- type: "send",
529
- data: msg,
530
- nodeId
531
- });
544
+ let hasFailures = false;
545
+ if (Array.isArray(msg.payload) && msg.payload.length && msg.payload[0] && typeof msg.payload[0].status === "string") {
546
+ const failed = msg.payload.filter(item => item.status !== "Good");
547
+ if (failed.length) {
548
+ hasFailures = true;
549
+ }
550
+ }
551
+ if (directError) {
552
+ hasFailures = true;
553
+ }
554
+
555
+ if (!hasFailures) {
556
+ process.send({
557
+ type: "send",
558
+ data: msg,
559
+ nodeId
560
+ });
561
+ }
532
562
 
533
563
  process.send({
534
564
  type: "status",
535
565
  data: {
536
- fill: "green",
566
+ fill: hasFailures ? (directError ? "red" : "yellow") : "green",
537
567
  shape: "dot",
538
- text:
539
- writtenPaths.length > 1
540
- ? `write ${writtenPaths.length} tags`
541
- : `write ${writtenPaths[0]}`
568
+ text: hasFailures
569
+ ? (directError ? "write failed" : "partial write failed")
570
+ : (writtenPaths.length > 1 ? `write ${writtenPaths.length} tags` : `write ${writtenPaths[0]}`)
542
571
  },
543
572
  nodeId
544
573
  });
@@ -582,6 +611,7 @@ class OpcUaServerProcess {
582
611
  text: "failed write"
583
612
  },
584
613
  error: error.message,
614
+ originalMsg: msg,
585
615
  nodeId
586
616
  });
587
617
  }
@@ -880,6 +910,222 @@ class OpcUaServerProcess {
880
910
  }
881
911
  }
882
912
 
913
+ async readActiveSessions(msg, nodeId) {
914
+ try {
915
+ await this.ensureReady();
916
+ const server = this.node && this.node.server;
917
+ if (!server || !server.engine) {
918
+ throw new Error("OPC UA server is not available");
919
+ }
920
+
921
+ const rawSessions = server.engine._sessions || {};
922
+ const sessions = Object.values(rawSessions).map((session) => buildSessionSnapshot(session));
923
+
924
+ if (msg) {
925
+ const outMsg = Object.assign({}, msg);
926
+ outMsg.payload = sessions;
927
+
928
+ process.send({
929
+ type: "send",
930
+ data: outMsg,
931
+ nodeId: nodeId
932
+ });
933
+ }
934
+
935
+ process.send({
936
+ type: "status",
937
+ data: {
938
+ fill: "green",
939
+ shape: "dot",
940
+ text: sessions.length === 1
941
+ ? "1 session"
942
+ : sessions.length + " sessions"
943
+ },
944
+ nodeId: nodeId
945
+ });
946
+ } catch (error) {
947
+ if (msg) {
948
+ process.send({
949
+ type: "error",
950
+ data: { fill: "red", shape: "ring", text: "failed getSessions" },
951
+ error: error.message,
952
+ originalMsg: msg,
953
+ nodeId: nodeId
954
+ });
955
+ } else {
956
+ process.send({
957
+ type: "status",
958
+ data: { fill: "red", shape: "ring", text: "failed getSessions: " + error.message },
959
+ nodeId: nodeId
960
+ });
961
+ }
962
+ }
963
+ }
964
+
965
+ async deleteActiveSessions(msg, nodeId) {
966
+ try {
967
+ await this.ensureReady();
968
+ const server = this.node && this.node.server;
969
+ if (!server || !server.engine) {
970
+ throw new Error("OPC UA server is not available");
971
+ }
972
+
973
+ const payload = msg && Array.isArray(msg.payload) ? msg.payload : [];
974
+ if (!payload.length) {
975
+ throw new Error("msg.payload must be a non-empty array of { sessionId } objects");
976
+ }
977
+
978
+ const engine = server.engine;
979
+ const rawSessions = engine._sessions || {};
980
+
981
+ const results = payload.map((item) => {
982
+ const requestedId = String(item && item.sessionId || "").trim();
983
+ if (!requestedId) {
984
+ return { sessionId: requestedId, status: "error", error: "sessionId is required" };
985
+ }
986
+
987
+ // Sessions are keyed by authenticationToken; find by matching nodeId (the GUID sessionId)
988
+ const found = Object.values(rawSessions).find(
989
+ (s) => safeToString(s.nodeId) === requestedId
990
+ );
991
+
992
+ if (!found) {
993
+ return { sessionId: requestedId, status: "not_found" };
994
+ }
995
+
996
+ try {
997
+ engine.closeSession(found.authenticationToken, true, "Forcing");
998
+ return { sessionId: requestedId, status: "deleted" };
999
+ } catch (closeError) {
1000
+ return { sessionId: requestedId, status: "error", error: closeError.message };
1001
+ }
1002
+ });
1003
+
1004
+ const deletedCount = results.filter((r) => r.status === "deleted").length;
1005
+ const notFoundCount = results.filter((r) => r.status === "not_found").length;
1006
+ const errorCount = results.filter((r) => r.status === "error").length;
1007
+
1008
+ if (msg) {
1009
+ const outMsg = Object.assign({}, msg);
1010
+ outMsg.payload = results;
1011
+
1012
+ process.send({
1013
+ type: "send",
1014
+ data: outMsg,
1015
+ nodeId: nodeId
1016
+ });
1017
+ }
1018
+
1019
+ const statusParts = [];
1020
+ if (deletedCount) statusParts.push("deleted " + deletedCount);
1021
+ if (notFoundCount) statusParts.push("not found " + notFoundCount);
1022
+ if (errorCount) statusParts.push("error " + errorCount);
1023
+
1024
+ process.send({
1025
+ type: "status",
1026
+ data: {
1027
+ fill: errorCount ? "red" : (notFoundCount ? "yellow" : "green"),
1028
+ shape: "dot",
1029
+ text: statusParts.join(", ") || "no sessions"
1030
+ },
1031
+ nodeId: nodeId
1032
+ });
1033
+ } catch (error) {
1034
+ if (msg) {
1035
+ process.send({
1036
+ type: "error",
1037
+ data: { fill: "red", shape: "ring", text: "failed deleteSessions" },
1038
+ error: error.message,
1039
+ originalMsg: msg,
1040
+ nodeId: nodeId
1041
+ });
1042
+ } else {
1043
+ process.send({
1044
+ type: "status",
1045
+ data: { fill: "red", shape: "ring", text: "failed deleteSessions: " + error.message },
1046
+ nodeId: nodeId
1047
+ });
1048
+ }
1049
+ }
1050
+ }
1051
+
1052
+ }
1053
+
1054
+ /**
1055
+ * Serializes a node-opcua ServerSession into a plain, IPC-safe object.
1056
+ */
1057
+ function buildSessionSnapshot(session) {
1058
+ return {
1059
+ sessionId: safeToString(session.nodeId),
1060
+ sessionName: String(session.sessionName || ""),
1061
+ status: String(session.__status || ""),
1062
+ creationDate: session.creationDate instanceof Date ? session.creationDate.toISOString() : null,
1063
+ sessionTimeout: safeNumber(session.sessionTimeout),
1064
+ clientLastContactTime: safeNumber(session.clientLastContactTime),
1065
+ channelId: session.channelId != null ? session.channelId : null,
1066
+ clientDescription: buildClientDescription(session.clientDescription),
1067
+ userIdentityToken: buildUserIdentityToken(session.userIdentityToken),
1068
+ channel: buildChannelInfo(session.channel),
1069
+ currentSubscriptionCount: safeNumber(session.currentSubscriptionCount),
1070
+ cumulatedSubscriptionCount: safeNumber(session.cumulatedSubscriptionCount),
1071
+ currentMonitoredItemCount: safeNumber(session.currentMonitoredItemCount),
1072
+ aborted: Boolean(session.aborted)
1073
+ };
1074
+ }
1075
+
1076
+ function safeToString(value) {
1077
+ try {
1078
+ return value != null ? String(value) : null;
1079
+ } catch (_) {
1080
+ return null;
1081
+ }
1082
+ }
1083
+
1084
+ function safeNumber(value) {
1085
+ const n = Number(value);
1086
+ return Number.isFinite(n) ? n : null;
1087
+ }
1088
+
1089
+ function buildClientDescription(desc) {
1090
+ if (!desc || typeof desc !== "object") {
1091
+ return null;
1092
+ }
1093
+ return {
1094
+ applicationUri: safeToString(desc.applicationUri),
1095
+ productUri: safeToString(desc.productUri),
1096
+ applicationName: desc.applicationName && desc.applicationName.text
1097
+ ? String(desc.applicationName.text)
1098
+ : safeToString(desc.applicationName),
1099
+ applicationType: safeToString(desc.applicationType)
1100
+ };
1101
+ }
1102
+
1103
+ function buildUserIdentityToken(token) {
1104
+ if (!token || typeof token !== "object") {
1105
+ return null;
1106
+ }
1107
+ return {
1108
+ policyId: safeToString(token.policyId),
1109
+ userName: safeToString(token.userName),
1110
+ // Never expose passwords or raw credential bytes
1111
+ tokenType: safeToString(token.schema && token.schema.name)
1112
+ };
1113
+ }
1114
+
1115
+ function buildChannelInfo(channel) {
1116
+ if (!channel || typeof channel !== "object") {
1117
+ return null;
1118
+ }
1119
+ return {
1120
+ channelId: channel.channelId != null ? channel.channelId : null,
1121
+ remoteAddress: safeToString(channel.remoteAddress),
1122
+ remotePort: safeNumber(channel.remotePort),
1123
+ bytesRead: safeNumber(channel.bytesRead),
1124
+ bytesWritten: safeNumber(channel.bytesWritten),
1125
+ transactionsCount: safeNumber(channel.transactionsCount),
1126
+ securityMode: safeToString(channel.securityMode),
1127
+ securityPolicy: safeToString(channel.securityPolicy)
1128
+ };
883
1129
  }
884
1130
 
885
1131
  /**
@@ -932,14 +1178,33 @@ process.on("message", async (msg) => {
932
1178
  break;
933
1179
 
934
1180
  case "buildServerSnapshot":
935
- OpcUaServerStatusNode(serverProcess.node, msg.msg, msg.nodeId)
936
- break
1181
+ try {
1182
+ await serverProcess.ensureReady();
1183
+ OpcUaServerStatusNode(serverProcess.node, msg.msg, msg.nodeId);
1184
+ } catch (error) {
1185
+ process.send({
1186
+ type: "status",
1187
+ data: {
1188
+ fill: msg.msg ? "red" : "yellow",
1189
+ shape: "ring",
1190
+ text: msg.msg ? "Status: " + error.message : "waiting for server"
1191
+ },
1192
+ nodeId: msg.nodeId
1193
+ });
1194
+ }
1195
+ break;
937
1196
  case "eventsServer":
938
1197
  eventsServer(serverProcess.node, msg.node, msg.nodeId)
939
1198
  break;
940
1199
  case "readActiveAlarms":
941
1200
  serverProcess.readActiveAlarms(msg.msg, msg.nodeId)
942
1201
  break;
1202
+ case "readActiveSessions":
1203
+ await serverProcess.readActiveSessions(msg.msg, msg.nodeId);
1204
+ break;
1205
+ case "deleteActiveSessions":
1206
+ await serverProcess.deleteActiveSessions(msg.msg, msg.nodeId);
1207
+ break;
943
1208
 
944
1209
 
945
1210
 
@@ -2,13 +2,17 @@
2
2
 
3
3
 
4
4
 
5
+ const path = require("path");
5
6
  const {
6
7
  OPCUAServer,
7
8
  UserTokenType,
8
9
  buildApplicationUri,
9
10
  makeRoles,
10
11
  WellKnownRoles,
11
- resolveNodeId
12
+ resolveNodeId,
13
+ OPCUACertificateManager,
14
+ SecurityPolicy,
15
+ MessageSecurityMode
12
16
  } = require("./opcua-constants");
13
17
  const { OpcUaAddressSpaceBuilder } = require("./opcua-address-space-builder");
14
18
  const { OpcUaServerMethods } = require("./opcua-server-methods");
@@ -29,13 +33,22 @@ class OpcUaServerRuntime {
29
33
  this.serverName = options.settings.serverName;
30
34
  this.port = options.settings.port;
31
35
  this.maxConnections = options.settings.maxConnections;
36
+ this.minSessionTimeout = options.settings.minSessionTimeout;
37
+ this.defaultSessionTimeout = options.settings.defaultSessionTimeout;
38
+ this.maxSessionTimeout = options.settings.maxSessionTimeout;
32
39
  this.namespaceUri = options.settings.namespaceUri;
33
40
  this.resourcePath = options.settings.resourcePath;
34
41
  this.allowAnonymous = options.settings.allowAnonymous;
42
+ this.automaticallyAcceptUnknownCertificate = options.settings.automaticallyAcceptUnknownCertificate;
43
+ this.certificatesFolder = options.settings.certificatesFolder;
35
44
  this.groups = options.settings.groups;
36
45
  this.users = options.settings.users;
37
- this.securityPolicy = options.settings.securityPolicy;
38
- this.securityMode = options.settings.securityMode;
46
+ this.securityPolicies = Array.isArray(options.settings.securityPolicies) && options.settings.securityPolicies.length > 0
47
+ ? options.settings.securityPolicies
48
+ : [SecurityPolicy.None];
49
+ this.securityModes = Array.isArray(options.settings.securityModes) && options.settings.securityModes.length > 0
50
+ ? options.settings.securityModes
51
+ : [MessageSecurityMode.None];
39
52
  this.treeConfig = options.settings.treeConfig;
40
53
 
41
54
  this.server = null;
@@ -52,6 +65,28 @@ class OpcUaServerRuntime {
52
65
  return;
53
66
  }
54
67
 
68
+ const certificateFolder = this.certificatesFolder || path.resolve(__dirname, "..", "..", "certificates");
69
+ this.serverCertificateManager = new OPCUACertificateManager({
70
+ rootFolder: certificateFolder,
71
+ automaticallyAcceptUnknownCertificate: this.automaticallyAcceptUnknownCertificate
72
+ });
73
+ await this.serverCertificateManager.initialize();
74
+
75
+ // Ensure directories exist immediately on startup
76
+ const fs = require("fs");
77
+ try {
78
+ const trustedDir = path.join(certificateFolder, "trusted", "certs");
79
+ const rejectedDir = path.join(certificateFolder, "rejected");
80
+ if (!fs.existsSync(trustedDir)) {
81
+ fs.mkdirSync(trustedDir, { recursive: true });
82
+ }
83
+ if (!fs.existsSync(rejectedDir)) {
84
+ fs.mkdirSync(rejectedDir, { recursive: true });
85
+ }
86
+ } catch (e) {
87
+ // Ignore directory creation errors
88
+ }
89
+
55
90
  this.server = new OPCUAServer(this.buildServerOptions());
56
91
  await this.server.initialize();
57
92
 
@@ -74,6 +109,7 @@ class OpcUaServerRuntime {
74
109
 
75
110
  this.addressSpaceBuilder.rebuild(this.treeConfig);
76
111
  await this.server.start();
112
+
77
113
  this.registry.registerServer(this);
78
114
 
79
115
  //Methods
@@ -200,9 +236,17 @@ class OpcUaServerRuntime {
200
236
  });
201
237
  }
202
238
 
239
+ const certificatesFolder = this.certificatesFolder || path.resolve(__dirname, "..", "..", "certificates");
240
+
203
241
  return {
204
242
  port: this.port,
243
+ minSessionTimeout: this.minSessionTimeout !== undefined ? this.minSessionTimeout : 100,
244
+ defaultSessionTimeout: this.defaultSessionTimeout !== undefined ? this.defaultSessionTimeout : 30000,
245
+ maxSessionTimeout: this.maxSessionTimeout !== undefined ? this.maxSessionTimeout : 3000000,
205
246
  resourcePath: this.resourcePath,
247
+ serverCertificateManager: this.serverCertificateManager,
248
+ certificateFile: path.join(certificatesFolder, "own", "certs", "server_selfsigned_cert_2048.pem"),
249
+ privateKeyFile: path.join(certificatesFolder, "own", "private", "private_key.pem"),
206
250
  buildInfo: {
207
251
  productName: "opc-ua-server",
208
252
  buildNumber: "1",
@@ -216,8 +260,8 @@ class OpcUaServerRuntime {
216
260
  applicationUri: buildApplicationUri(this.serverName),
217
261
  productUri: "urn:node-red:opc-ua-server"
218
262
  },
219
- securityPolicies: [this.securityPolicy],
220
- securityModes: [this.securityMode],
263
+ securityPolicies: this.securityPolicies,
264
+ securityModes: this.securityModes,
221
265
  allowAnonymous: this.allowAnonymous,
222
266
  userManager: {
223
267
  isValidUser: (username, password) => this.isValidUser(username, password),
@@ -10,13 +10,6 @@ function OpcUaServerStatusNode(node, msg, nodeId) {
10
10
  const serverNode = resolveRegisteredServer(node, msg, registry);
11
11
  const snapshot = buildServerSnapshot(serverNode);
12
12
 
13
- msg.payload = snapshot;
14
- msg.opcua = msg.opcua || {};
15
- msg.opcua.server = snapshot.identity.serverRef;
16
- msg.opcua.endpointUrl = snapshot.endpointUrl;
17
-
18
-
19
-
20
13
  process.send({
21
14
  type: "status",
22
15
  data: {
@@ -27,11 +20,18 @@ function OpcUaServerStatusNode(node, msg, nodeId) {
27
20
  nodeId: nodeId
28
21
  });
29
22
 
30
- process.send({
31
- type: "send",
32
- data: msg,
33
- nodeId: nodeId
34
- });
23
+ if (msg) {
24
+ msg.payload = snapshot;
25
+ msg.opcua = msg.opcua || {};
26
+ msg.opcua.server = snapshot.identity.serverRef;
27
+ msg.opcua.endpointUrl = snapshot.endpointUrl;
28
+
29
+ process.send({
30
+ type: "send",
31
+ data: msg,
32
+ nodeId: nodeId
33
+ });
34
+ }
35
35
 
36
36
 
37
37
  } catch (error) {
@@ -41,9 +41,9 @@ function OpcUaServerStatusNode(node, msg, nodeId) {
41
41
  process.send({
42
42
  type: "status",
43
43
  data: {
44
- fill: "red",
44
+ fill: msg ? "red" : "yellow",
45
45
  shape: "ring",
46
- text: "Status: " + error
46
+ text: msg ? "Status: " + error.message : "waiting for server"
47
47
  },
48
48
  nodeId: nodeId
49
49
  });
@@ -0,0 +1,25 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIENTCCAx2gAwIBAgIHAXgZZJFWWTANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG
3
+ EwJGUjEQMA4GA1UEBxMHT3JsZWFuczERMA8GA1UEChMIU3RlcmZpdmUxFjAUBgNV
4
+ BAMMDW15U2VydmVyMUB0dWYwHhcNMjYwNjIwMTQxNTE1WhcNMzYwNjE3MTQxNTE1
5
+ WjBKMQswCQYDVQQGEwJGUjEQMA4GA1UEBxMHT3JsZWFuczERMA8GA1UEChMIU3Rl
6
+ cmZpdmUxFjAUBgNVBAMMDW15U2VydmVyMUB0dWYwggEiMA0GCSqGSIb3DQEBAQUA
7
+ A4IBDwAwggEKAoIBAQC7IYbSbk1mosq3NdM494XdHfuLulEf07RmRRcXhv53/iPC
8
+ HTzTpyyaT9P2KItUEMf1+1m26O53gl8BlwbS+oCuDt34ORO0dWDoftgBXjP0uUWz
9
+ seaZ7AVwXL1yorYAK11VLHU4cxfzVLKK5WbiB+qEiQSUG+EKHlEtmyIEbrsOGh8s
10
+ ZZCE4rFjavzSaCGN7bwqNMtGyFPS5FGZ8HvvtLqhzyz0ew0TaZKpnaFQGxtvGI68
11
+ 6yICgutmSXqyII8OHCXQ751gLzbhvADVUf/CvhX60ZCDMcGBQcFeLPkZF4CfQ2OP
12
+ 2OZkm/2ulS+NZXWqDFX6pvN/Zsy57q4RKR+x+nDFAgMBAAGjggEeMIIBGjBVBglg
13
+ hkgBhvhCAQ0ESAxGU2VsZi1zaWduZWQgY2VydGlmaWNhdGUgZ2VuZXJhdGVkIGJ5
14
+ IE5vZGUtT1BDVUEgQ2VydGlmaWNhdGUgdXRpbGl0eSBWMjAMBgNVHRMBAf8EAjAA
15
+ MCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAOBgNVHQ8BAf8EBAMC
16
+ AvQwHQYDVR0OBBYEFF3kmynfd5siPu9cso8NLIdURx8+MB8GA1UdIwQYMBaAFF3k
17
+ mynfd5siPu9cso8NLIdURx8+MEEGA1UdEQQ6MDiCA1RVRoIDdHVmhwTAqGQBhwTA
18
+ qA9khwTAqBEBhhp1cm46dHVmOm5vZGUtcmVkOm15c2VydmVyMTANBgkqhkiG9w0B
19
+ AQsFAAOCAQEAkDutnUHoeK6CQmYlTV2pJPW+1qcJ9QDCrDEJjoMReWY97CQqrPxm
20
+ 9/nTQtPiHedsiF7LbOqsPpiK/chEACSaQO+OYzGtMydKehlC89KUG26TH+OgtVjM
21
+ zVi3sfSpo33jJ1T1Z8YKw9rnOfjkWzfMa6RW4+4p1DNR4RJcvKsNRTkh/C8RDFr0
22
+ ZPave1jxaYpxPQGHKD1lqQD6uIGaYwAogkQDn41Bl1/PwC79gOgs0WmKDZuQ3BpR
23
+ wGSa6Bcqzj3zzBQapSs5fFjuUyowaFsGI48N3mJJx4LlYB17yuOD5R6a6nzVJyaL
24
+ QsKqGvKkNFP0c3F1H+pkUGFGgR9PkkA5Xg==
25
+ -----END CERTIFICATE-----
@@ -0,0 +1,72 @@
1
+ ##################################################################################################
2
+ ## SIMPLE OPENSSL CONFIG FILE FOR SELF-SIGNED CERTIFICATE GENERATION
3
+ ################################################################################################################
4
+
5
+ distinguished_name = req_distinguished_name
6
+ default_md = sha1
7
+
8
+ default_md = sha256 # The default digest algorithm
9
+
10
+ [ v3_ca ]
11
+ subjectKeyIdentifier = hash
12
+ authorityKeyIdentifier = keyid:always,issuer:always
13
+
14
+ # authorityKeyIdentifier = keyid
15
+ basicConstraints = CA:TRUE
16
+ keyUsage = critical, cRLSign, keyCertSign
17
+ nsComment = "Self-signed Certificate for CA generated by Node-OPCUA Certificate utility"
18
+ #nsCertType = sslCA, emailCA
19
+ #subjectAltName = email:copy
20
+ #issuerAltName = issuer:copy
21
+ #obj = DER:02:03
22
+ # crlDistributionPoints = @crl_info
23
+ # [ crl_info ]
24
+ # URI.0 = http://localhost:8900/crl.pem
25
+ subjectAltName = $ENV::ALTNAME
26
+
27
+ [ req ]
28
+ days = 390
29
+ req_extensions = v3_req
30
+ x509_extensions = v3_ca
31
+
32
+ [v3_req]
33
+ basicConstraints = CA:false
34
+ keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment
35
+ subjectAltName = $ENV::ALTNAME
36
+
37
+ [ v3_ca_signed]
38
+ subjectKeyIdentifier = hash
39
+ authorityKeyIdentifier = keyid,issuer
40
+ basicConstraints = critical, CA:FALSE
41
+ keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment
42
+ extendedKeyUsage = clientAuth,serverAuth
43
+ nsComment = "certificate generated by Node-OPCUA Certificate utility and signed by a CA"
44
+ subjectAltName = $ENV::ALTNAME
45
+ [ v3_selfsigned]
46
+ subjectKeyIdentifier = hash
47
+ authorityKeyIdentifier = keyid,issuer
48
+ basicConstraints = critical, CA:FALSE
49
+ keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment
50
+ extendedKeyUsage = clientAuth,serverAuth
51
+ nsComment = "Self-signed certificate generated by Node-OPCUA Certificate utility"
52
+ subjectAltName = $ENV::ALTNAME
53
+ [ req_distinguished_name ]
54
+ countryName = Country Name (2 letter code)
55
+ countryName_default = FR
56
+ countryName_min = 2
57
+ countryName_max = 2
58
+ # stateOrProvinceName = State or Province Name (full name)
59
+ # stateOrProvinceName_default = Ile de France
60
+ # localityName = Locality Name (city, district)
61
+ # localityName_default = Paris
62
+ organizationName = Organization Name (company)
63
+ organizationName_default = NodeOPCUA
64
+ # organizationalUnitName = Organizational Unit Name (department, division)
65
+ # organizationalUnitName_default = R&D
66
+ commonName = Common Name (hostname, FQDN, IP, or your name)
67
+ commonName_max = 256
68
+ commonName_default = NodeOPCUA
69
+ # emailAddress = Email Address
70
+ # emailAddress_max = 40
71
+ # emailAddress_default = node-opcua (at) node-opcua (dot) com
72
+ subjectAltName = $ENV::ALTNAME
@@ -0,0 +1,28 @@
1
+ -----BEGIN PRIVATE KEY-----
2
+ MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7IYbSbk1mosq3
3
+ NdM494XdHfuLulEf07RmRRcXhv53/iPCHTzTpyyaT9P2KItUEMf1+1m26O53gl8B
4
+ lwbS+oCuDt34ORO0dWDoftgBXjP0uUWzseaZ7AVwXL1yorYAK11VLHU4cxfzVLKK
5
+ 5WbiB+qEiQSUG+EKHlEtmyIEbrsOGh8sZZCE4rFjavzSaCGN7bwqNMtGyFPS5FGZ
6
+ 8HvvtLqhzyz0ew0TaZKpnaFQGxtvGI686yICgutmSXqyII8OHCXQ751gLzbhvADV
7
+ Uf/CvhX60ZCDMcGBQcFeLPkZF4CfQ2OP2OZkm/2ulS+NZXWqDFX6pvN/Zsy57q4R
8
+ KR+x+nDFAgMBAAECggEAGofM0Q3BXIFNAz+W1DdHm8tR7AP812nQ5ET8WqIRdtqp
9
+ oC47/vfvG2ug7f/ejQsaBnZdyFBq6repl5Sda5EHaGYEM1qIQCf6FsxQ/JSqAhK4
10
+ XpskygLL3JvRYizOZ+S+BULZ1ah/p0iFTarrdLVRmvvAEe2H8MLOmIwrfPxj+cId
11
+ Lb02xSX3FEf7TC4fUkTJQP52PDNT/oIZhUE807tBmlCLhAIKg3DaZhnAXILpY9q6
12
+ HWbR1lZffzz912XY2fOeHhZI6yKH2BcciVMbP3MEuFLaEQKyYpQCYIraBlcYcGNT
13
+ 8pyIPBukaejOJ08MHZQrh6PFYzZrISRJHVriFYDfuwKBgQDm3T1UOq3DBOOo7TvG
14
+ VgNSfxZaXRCAua12qM9f0iz7DA5waFQ8l+0oHcBikRtuvaxGq9kfmINFqUQEow4w
15
+ YXloR5AdNgub4Q8Wb/kMYr1Qq750q5MvavhxT2PKNzONQ5f0g9E2DciSVoZeVSK4
16
+ 6q+ZyuodXw2ahLS5pJUSBCCFIwKBgQDPgVUakeePBL+g0Oy5i8DuuTErj1h2J/dA
17
+ IYDvA3MvccQMJNf1tKkDfTdXZd/CG4JL5JNYlCzPT7V2KInXrL8sFWi6/Y+t1MXA
18
+ E+LHI33Il4jbBBvWx9ItyBS6oouANGaO4pQZL0c720hGffK246P0RiER8T1fdeS3
19
+ JPv+ylPU9wKBgDeQFbuY58sg+R3mAtXoS6JmPd3/ugIRLiN523cnYXYGX89D/Moc
20
+ kpJuHqhaXizX74eOwpHtJeL1Kw6mo7qXKx4i4xd0s3SPxQ7UYi9N8FxjCVKRHLpz
21
+ 11mGDvFTOdAM7ZyGwSpuRNCbjHlVqiaxLRQplxD8mIyQ1eI8LziHz7/bAoGBAMBy
22
+ VWh/+v8ES2kteu8Wcwe0D6szlbp3lHMQ35BMZc6Rt13/6Z6CP+Hxhpry65QNiUkz
23
+ o4gaXHikl0oPjM/O8bpD3M7XjSKN3B0pFEDWZLjd+VoOtHb8+avmDXuOdsyfTKKl
24
+ 9u5oj6su0xg1hR4jf5J0XAVU9DONlmJY1bFXGmq/AoGAZmCwBdOA830uETdh3AOb
25
+ cI8F1SozJOqGbTrl7GzyzOUvFxsMkD9NOHCI4LD6sDRdJM1CE1As33hNKG2v9B+C
26
+ /MTpbWsTWCAmMhAy7QUXMqDq/g5J2WbfhcXErGps4fQxJzVt1sapedIzFBw9m5XP
27
+ QVMSTmXF6C3wg3QbzTVsQTM=
28
+ -----END PRIVATE KEY-----
@@ -0,0 +1,25 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEKjCCAxKgAwIBAgIHAXdVh2g4JzANBgkqhkiG9w0BAQsFADBRMQswCQYDVQQG
3
+ EwJGUjEQMA4GA1UEBxMHT3JsZWFuczERMA8GA1UEChMIU3RlcmZpdmUxHTAbBgNV
4
+ BAMMFE5vZGVPUENVQS1DbGllbnRAdHVmMB4XDTI2MDQwNzE4NDgwM1oXDTM2MDQw
5
+ NDE4NDgwM1owUTELMAkGA1UEBhMCRlIxEDAOBgNVBAcTB09ybGVhbnMxETAPBgNV
6
+ BAoTCFN0ZXJmaXZlMR0wGwYDVQQDDBROb2RlT1BDVUEtQ2xpZW50QHR1ZjCCASIw
7
+ DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMhBslFMtRXQ2Ww7JAtPLoM7I1s
8
+ QP7mmHOv0U7mcSLib/yksMNT0G2U5J1EHI+Km1JwTYXujJnzi/ouuuQsWUsm3zP6
9
+ KAO1XzQuIYf8iEBblzOCA53eTvo056zNfeDoUb9l1CfQH/H6sL2js786dUpuJCG9
10
+ fuCfgrExRbzZQrELcduwRPuVio770NK086orAzFIXaRM20F4HMkTtorsRoGUIU5s
11
+ u6Fqy9nmdKY4w4JHQMafO3L1lHEbGuVwZmmkXmTQtBIS6W8tPSa9fh7GrlHJP4Zc
12
+ cgcp/xuXcpWfHjJaAmUQtCuNprlywJBChlstWkJ09zj1VvqoAWd0GL7ehQkCAwEA
13
+ AaOCAQUwggEBMFUGCWCGSAGG+EIBDQRIDEZTZWxmLXNpZ25lZCBjZXJ0aWZpY2F0
14
+ ZSBnZW5lcmF0ZWQgYnkgTm9kZS1PUENVQSBDZXJ0aWZpY2F0ZSB1dGlsaXR5IFYy
15
+ MAwGA1UdEwEB/wQCMAAwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
16
+ MA4GA1UdDwEB/wQEAwIC9DAdBgNVHQ4EFgQUVOT0LzYI7XAMQ11FOV/+tUCUkvYw
17
+ HwYDVR0jBBgwFoAUVOT0LzYI7XAMQ11FOV/+tUCUkvYwKAYDVR0RBCEwH4IDdHVm
18
+ hhh1cm46dHVmOk5vZGVPUENVQS1DbGllbnQwDQYJKoZIhvcNAQELBQADggEBABiN
19
+ x0XNf1nDyRyJQCQ4GMS9e/xrjO3FV106IJRPEosoB10R7zBL92ra4+3AilGnNOeM
20
+ 1O5eIel67DNL2kjw+5ggagtOmhJ3g3ZXFMpF08BeKnMwavoLs74yBZVFDq+2fOxs
21
+ kDdMX5TOpC4kZHMG5G9Cha9mcWjYSAYWVko/WCfby4D+MQiwraAraDL12uFcRVnP
22
+ htDTuNxs+dfKefiIsTgSlkJMisfGEV/EzmwSsTpvtuUZ5DwKddolRGsB/cXqTjc0
23
+ vGxHFjsuqp77gUyb9LNqE8ENi7pOZQFFhAmjSXTXcklWVynycgQ1E0TSNNQio4Xi
24
+ QZtA1NgPnLI6b2kubUQ=
25
+ -----END CERTIFICATE-----