Skip to content
Permalink
Browse files Browse the repository at this point in the history
fix message chunk overflow detection
  • Loading branch information
erossignon committed Jun 2, 2022
1 parent dbcb5d5 commit 33ca3ba
Show file tree
Hide file tree
Showing 38 changed files with 1,093 additions and 439 deletions.
36 changes: 23 additions & 13 deletions packages/node-opcua-client/source/client_base.ts
Expand Up @@ -8,19 +8,9 @@ import { OPCUACertificateManager } from "node-opcua-certificate-manager";
import { OPCUASecureObject } from "node-opcua-common";
import { Certificate } from "node-opcua-crypto";
import { ObjectRegistry } from "node-opcua-object-registry";
import {
ClientSecureChannelLayer,
ConnectionStrategy,
ConnectionStrategyOptions,
SecurityPolicy} from "node-opcua-secure-channel";
import {
FindServersOnNetworkRequestOptions,
FindServersRequestOptions,
ServerOnNetwork
} from "node-opcua-service-discovery";
import {
ApplicationDescription,
EndpointDescription} from "node-opcua-service-endpoints";
import { ClientSecureChannelLayer, ConnectionStrategy, ConnectionStrategyOptions, SecurityPolicy } from "node-opcua-secure-channel";
import { FindServersOnNetworkRequestOptions, FindServersRequestOptions, ServerOnNetwork } from "node-opcua-service-discovery";
import { ApplicationDescription, EndpointDescription } from "node-opcua-service-endpoints";
import { ChannelSecurityToken, MessageSecurityMode } from "node-opcua-service-secure-channel";
import { ErrorCallback } from "node-opcua-status-code";

Expand Down Expand Up @@ -49,6 +39,22 @@ export interface FindEndpointResult {

export type FindEndpointCallback = (err: Error | null, result?: FindEndpointResult) => void;

export interface TransportSettings {
maxChunkCount?: number;
/**
* @advanced
*/
maxMessageSize?: number;
/**
* @advanced
*/
sendBufferSize?: number;
/**
* @advanced
*/
receiveBufferSize?: number;
}

export interface OPCUAClientBaseOptions {
/**
* the client application name
Expand Down Expand Up @@ -131,6 +137,10 @@ export interface OPCUAClientBaseOptions {
* discovery url:
*/
discoveryUrl?: string;
/**
* @advanced
*/
transportSetting?: TransportSettings
}

export interface GetEndpointsOptions {
Expand Down
Expand Up @@ -622,7 +622,10 @@ export class ClientBaseImpl extends OPCUASecureObject implements OPCUAClientBase
securityMode: this.securityMode,
securityPolicy: this.securityPolicy,
serverCertificate: this.serverCertificate,
tokenRenewalInterval: this.tokenRenewalInterval
tokenRenewalInterval: this.tokenRenewalInterval,

// transportTimeout:

});
secureChannel.protocolVersion = this.protocolVersion;

Expand Down
15 changes: 8 additions & 7 deletions packages/node-opcua-client/test/test_x509_signature.ts
Expand Up @@ -10,7 +10,7 @@ import { decodeExpandedNodeId } from "node-opcua-basic-types";
import { BinaryStream } from "node-opcua-binary-stream";
import { Certificate, PrivateKeyPEM, readCertificate, readPrivateKeyPEM, split_der } from "node-opcua-crypto";
import { makeBufferFromTrace } from "node-opcua-debug";
import { constructObject } from "node-opcua-factory";
import { BaseUAObject, constructObject } from "node-opcua-factory";
import {
computeSignature,
getCryptoFactory,
Expand Down Expand Up @@ -39,13 +39,14 @@ function readMessage(name: string): Buffer {
}

async function decodeMessage(buffer: Buffer): Promise<any> {
/*
const offset = 16 * 3 + 6;
buffer = buffer.slice(offset);
*/
const messageBuilder = new MessageBuilder({});
const messageBuilder = new MessageBuilder({
maxChunkCount: 1,
maxChunkSize: buffer.length + 100,
maxMessageSize: buffer.length + 100
});

messageBuilder.setSecurity(MessageSecurityMode.None, SecurityPolicy.None);
let objMessage: any = null;
let objMessage: BaseUAObject | null = null;
messageBuilder.once("full_message_body", (fullMessageBody: Buffer) => {
const stream = new BinaryStream(fullMessageBody);
const id = decodeExpandedNodeId(stream);
Expand Down
@@ -1,29 +1,29 @@
import {allPermissions, OPCUAClient, OPCUAServer, StatusCodes, UserTokenType, WellKnownRoles, makeRoles} from "node-opcua";
import { allPermissions, OPCUAClient, OPCUAServer, StatusCodes, UserTokenType, WellKnownRoles, makeRoles } from "node-opcua";
import "should";

const describe = require("node-opcua-leak-detector").describeWithLeakDetector;
describe("Issue #896: Check Authorization for UAMethods", () => {
const users = [
{username: "Gandalf", password: "g", roles: makeRoles([WellKnownRoles.AuthenticatedUser,WellKnownRoles.ConfigureAdmin])},
{username: "Frodo", password: "f", roles: makeRoles([WellKnownRoles.AuthenticatedUser])},
{ username: "Gandalf", password: "g", roles: makeRoles([WellKnownRoles.AuthenticatedUser, WellKnownRoles.ConfigureAdmin]) },
{ username: "Frodo", password: "f", roles: makeRoles([WellKnownRoles.AuthenticatedUser]) }
];

const port = 2226;
const server = new OPCUAServer({
port,
userManager: {
getUserRoles: username => users.find(user => user.username === username)!.roles,
isValidUser(username, password) {
const user = users.find(user => user.username === username);
getUserRoles: (username) => users.find((user) => user.username === username)!.roles,

isValidUser: (username: string, password: string) => {
const user = users.find((user) => user.username === username);
if (!user) return false;
return user.password === password;
}
}
})
});

const client = OPCUAClient.create({
endpointMustExist: false,
endpointMustExist: false
});

let wasExecuted: boolean;
Expand All @@ -36,24 +36,26 @@ describe("Issue #896: Check Authorization for UAMethods", () => {
browseName: "e2e",
nodeId: "ns=1;s=e2e"
});
namespace.addMethod(folder, {
browseName: "doIt",
nodeId: "ns=1;s=doIt",
rolePermissions: [
{
roleId: WellKnownRoles.ConfigureAdmin,
permissions: allPermissions
}
]
/*
namespace
.addMethod(folder, {
browseName: "doIt",
nodeId: "ns=1;s=doIt",
rolePermissions: [
{
roleId: WellKnownRoles.ConfigureAdmin,
permissions: allPermissions
}
]
/*
permissions: {
[Permission.Call]: ["!*", WellKnownRoles.ConfigureAdmin]
}
*/
}).bindMethod((inputArguments, context, callback) => {
wasExecuted = true;
callback(null, {statusCode: StatusCodes.Good})
});
})
.bindMethod((inputArguments, context, callback) => {
wasExecuted = true;
callback(null, { statusCode: StatusCodes.Good });
});
await server.start();
return client.connect(`opc.tcp://localhost:${port}/UA/NodeOPCUA`);
});
Expand All @@ -63,7 +65,7 @@ describe("Issue #896: Check Authorization for UAMethods", () => {
await server.shutdown();
});

beforeEach(() => wasExecuted = false);
beforeEach(() => (wasExecuted = false));

it("should allow Gandalf to execute the method", async () => {
const clientSession = await client.createSession({
Expand All @@ -74,7 +76,7 @@ describe("Issue #896: Check Authorization for UAMethods", () => {
const result = await clientSession.call({
methodId: "ns=1;s=doIt",
objectId: "ns=1;s=e2e",
inputArguments: [],
inputArguments: []
});
await clientSession.close();
result.statusCode.should.eql(StatusCodes.Good);
Expand All @@ -90,10 +92,10 @@ describe("Issue #896: Check Authorization for UAMethods", () => {
const result = await clientSession.call({
methodId: "ns=1;s=doIt",
objectId: "ns=1;s=e2e",
inputArguments: [],
inputArguments: []
});
await clientSession.close();
result.statusCode.should.eql(StatusCodes.BadUserAccessDenied);
wasExecuted.should.eql(false);
});
});
});
@@ -1,10 +1,5 @@
/*global xit,it,describe,before,after,beforeEach,afterEach*/
"use strict";




const { assert } = require("node-opcua-assert");
const async = require("async");
const should = require("should");
const sinon = require("sinon");
Expand Down
Expand Up @@ -34,7 +34,7 @@ module.exports = function (test) {

beforeEach(function (done) {
client = OPCUAClient.create({
requestedSessionTimeout: 600 * 1000 // use long session time out
requestedSessionTimeout: 600 * 1000, // use long session time out
});
endpointUrl = test.endpointUrl;
done();
Expand Down Expand Up @@ -270,7 +270,7 @@ module.exports = function (test) {
});

it("Q3-5 should return BadTooManyOperations when CallRequest has too many methods to call", function (done) {
const too_many = 50000;
const too_many = 5000;
const methodToCalls = [];
for (let i = 0; i < too_many; i++) {
methodToCalls.push({
Expand Down
@@ -1,18 +1,16 @@
const async = require("async");
const should = require("should");
const chalk = require("chalk");
const {
AttributeIds,
VariableIds,
OPCUAClient,
resolveNodeId,
ClientMonitoredItem,
StatusCodes,
TimestampsToReturn,
MonitoringMode
} = require("node-opcua");
const { make_debugLog, make_errorLog, checkDebugFlag } = require("node-opcua-debug");
const { make_debugLog, checkDebugFlag } = require("node-opcua-debug");
const { perform_operation_on_subscription_async } = require("../../test_helpers/perform_operation_on_client_session");
const { pause } = require("../discovery/_helper");

function f(func) {
return function (callback) {
Expand All @@ -27,6 +25,9 @@ const doDebug = checkDebugFlag("TEST");

let sessionCounter = 0;
async function connectAndCreateSession(endpointUrl) {

await pause(100);

const client = OPCUAClient.create({
name: "client" + sessionCounter++,
});
Expand All @@ -36,6 +37,7 @@ async function connectAndCreateSession(endpointUrl) {
}

async function closeSessionAndDisconnect({ client, session }) {
await pause(100);
await session.close();
await client.disconnect();
}
Expand Down Expand Up @@ -65,8 +67,9 @@ async function installMonitoredItem(subscription, nodeId) {
});
return await new Promise((resolve, reject) => {
const timer = setTimeout(() => {
console.log(monitoredItem);
reject(new Error("Never received changedx for id" + nodeId.toString()));
}, 5000);
}, 15000);

monitoredItem.once("changed", function (dataValue) {
clearTimeout(timer);
Expand All @@ -85,17 +88,19 @@ async function installCumulatedSessionCounter(subscription) {

async function waitSessionCountChange(currentSessionCountMonitoredItem) {

return await new Promise((resolve,reject) => {
return await new Promise((resolve, reject) => {
const timer = setTimeout(() => {
console.log(currentSessionCountMonitoredItem);
reject(new Error("Never received ", currentSessionCountMonitoredItem.toString()));
}, 5000);
}, 15000);

currentSessionCountMonitoredItem.once("changed", function (dataValue) {
clearTimeout(timer);
const new_currentSessionCount = dataValue.value.value;
debugLog("new currentSessionCount=", dataValue.toString());
resolve(new_currentSessionCount);
});

});
}

Expand All @@ -106,7 +111,7 @@ module.exports = function (test) {

const client = OPCUAClient.create({});

await perform_operation_on_subscription_async(client, endpointUrl, async function (session, subscription) {
await perform_operation_on_subscription_async(client, endpointUrl, async (session, subscription) => {
const [recordedCurrentSessionCountValues, currentSessionCountMonitoredItem] = await installCurrentSessionCounter(
subscription
);
Expand All @@ -124,6 +129,7 @@ module.exports = function (test) {
const promises = [waitSessionCountChange(currentSessionCountMonitoredItem), connectAndCreateSession(endpointUrl)];
return await Promise.all(promises);
}

async function disconnectAndWaitCurrentSessionCountChange({ client, session }) {
debugLog("disconnecting", session.name);

Expand Down
@@ -1,3 +1,4 @@
import { clearTimeout } from "timers";
import {
AddressSpace,
assert,
Expand All @@ -18,12 +19,10 @@ import {
StatusCode,
TimestampsToReturn
} from "node-opcua";
import sinon = require("sinon");
import should = require("should");
import * as should from "should";

import { make_debugLog, checkDebugFlag } from "node-opcua-debug";
import { itemsToMonitor1 } from "./_helpers_items_to_monitor";
import { clearTimeout } from "timers";
const debugLog = make_debugLog("TEST");
const doDebug = checkDebugFlag("TEST");

Expand Down Expand Up @@ -118,12 +117,16 @@ export function t(test: any) {
it("Should monitor a large number of node efficiently", async () => {
const { session, subscription, publishEngine } = s;

session.on("session_closed", ()=>{
console.log("session_closed");
});

const namespaceArray = await session.readNamespaceArray();
const simulationNamespaceIndex = namespaceArray.indexOf("urn://node-opcua-simulator");
console.log("simulationNamespaceIndex = ", simulationNamespaceIndex);

let itemToMonitors: ReadValueIdOptions[] = itemsToMonitor1;
while (itemToMonitors.length + itemsToMonitor1.length < 10000) {
while (itemToMonitors.length + itemsToMonitor1.length < 2200) {
itemToMonitors = itemToMonitors.concat([...itemsToMonitor1]);
}

Expand Down Expand Up @@ -156,7 +159,10 @@ export function t(test: any) {
console.time("B");

await new Promise<void>((resolve) => {
const timerId = setTimeout(() => resolve(), 12000);


const timerId = setTimeout(() => resolve(), 5000);

group.on("changed", (monitoredItem, dataValue, index) => {
counter++;
if (counter === itemToMonitors.length) {
Expand Down

0 comments on commit 33ca3ba

Please sign in to comment.