Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions lib/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,28 @@ function convertMessage(topic, message, adapter, clientID) {
const parts = message.split(',');
try {
let str = '';
let validCharCodes = true;

// First validate all parts are valid character codes
for (let p = 0; p < parts.length; p++) {
str += String.fromCharCode(parseInt(parts[p].trim(), 10));
const charCode = parseInt(parts[p].trim(), 10);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot To prevent double "parseInt" there should be no issue to start to build the strig as long as characters as value but just stop that at the first invalid char. Only when all chars were valid you use the build string. So you prevent duplicate logic

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optimized the implementation to build the string and validate character codes in a single pass. Now only one parseInt call per part is made, and the loop stops immediately at the first invalid character code. The converted string is only used if all parts were valid. (commit 75aeaaa)

// Only allow values that work reliably with String.fromCharCode (0-65535)
// and are reasonable character codes (typically 0-255 for extended ASCII)
if (charCode < 0 || charCode > 255) {
validCharCodes = false;
break;
}
}

// Only convert if all parts are valid character codes
if (validCharCodes) {
for (let p = 0; p < parts.length; p++) {
str += String.fromCharCode(parseInt(parts[p].trim(), 10));
}
message = str;
// Character code conversion complete - don't try to parse as number later
return message;
}
message = str;
} catch {
// cannot convert and ignore it
}
Expand Down
40 changes: 40 additions & 0 deletions test/testConvert.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,44 @@ describe('Test convert version', function () {
it('Number', async () => {
expect(convertMessage('data', '233.57')).to.be.equal(233.57);
});

it('Character code conversion - valid ASCII codes', async () => {
expect(convertMessage('data', '65,66,67')).to.be.equal('ABC');
expect(convertMessage('data', '72,101,108,108,111')).to.be.equal('Hello');
expect(convertMessage('data', '32,87,111,114,108,100')).to.be.equal(' World');
});

it('Character code conversion - invalid codes should remain unchanged', async () => {
// NUKI 3.0 Pro lock data - should NOT be converted
expect(convertMessage('data', '3,0,442236930,1,2')).to.be.equal('3,0,442236930,1,2');

// Values above 255 should NOT be converted
expect(convertMessage('data', '256,512,1024')).to.be.equal('256,512,1024');
expect(convertMessage('data', '70000,80000,90000')).to.be.equal('70000,80000,90000');

// Negative numbers should NOT be converted
expect(convertMessage('data', '-1,2,3')).to.be.equal('-1,2,3');

// Mix of valid and invalid should NOT be converted
expect(convertMessage('data', '0,65535,1114112')).to.be.equal('0,65535,1114112');
});

it('Character code conversion - edge cases', async () => {
// Control characters (0-31) are valid
expect(convertMessage('data', '9,10,13')).to.be.equal('\t\n\r');

// Extended ASCII (128-255) is valid
expect(convertMessage('data', '128,129,130')).to.be.equal('\x80\x81\x82');

// Single number doesn't match pattern (requires at least 3 numbers) but may be converted to number
expect(convertMessage('data', '65')).to.be.equal(65); // String '65' becomes number 65
expect(convertMessage('data', '65,66')).to.be.equal(65.66); // Two numbers: '65,66' -> '65.66' -> 65.66
});

it('Character code conversion - non-numeric data unchanged', async () => {
expect(convertMessage('data', 'hello,world')).to.be.equal('hello,world');
expect(convertMessage('data', 'a,b,c')).to.be.equal('a,b,c');
expect(convertMessage('data', '1,2,abc')).to.be.equal('1,2,abc');
expect(convertMessage('data', '3.14,2.71,1.41')).to.be.equal('3.14,2.71,1.41');
});
});