From 76bda928f85778edada4ee0ae10480a0cc7d3859 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Mon, 13 May 2024 19:09:48 +0800 Subject: [PATCH] feat: validate the class name --- .github/workflows/nodejs.yml | 9 +++----- lib/utils.js | 40 ++++++++++++++++++++++++++++++++++++ lib/v2/decoder.js | 6 +++--- test/special_cases.test.js | 20 +++++++++++++++++- 4 files changed, 65 insertions(+), 10 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index c84f3aa..2133283 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -3,19 +3,16 @@ name: CI on: push: branches: [ master, 1.x ] - pull_request: branches: [ master, 1.x ] - workflow_dispatch: {} - jobs: Job: name: Node.js - uses: artusjs/github-actions/.github/workflows/node-test.yml@master + uses: node-modules/github-actions/.github/workflows/node-test.yml@master with: os: 'ubuntu-latest' - version: '8, 10, 12, 14, 16, 18' + version: '8, 10, 12, 14, 16, 18, 20, 22' build-with-zig: strategy: @@ -125,4 +122,4 @@ jobs: set -e ${{ matrix.settings.setup }} apt update apt install make - make test-v2rust \ No newline at end of file + make test-v2rust diff --git a/lib/utils.js b/lib/utils.js index 8a94f0c..67d0218 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -91,3 +91,43 @@ exports.float32Test = function float32Test(input) { var output = FLOAT_TEST_BUF.readFloatBE(0); return output === input; }; + +var REG_VALID_ID = /^([a-zA-Z_$][a-zA-Z\d_$]*)$/; + +function isValidIdentifier(str) { + return REG_VALID_ID.test(str); +} + +exports.isValidIdentifier = isValidIdentifier; + +exports.ensureValidIdentifier = function ensureValidIdentifier(str) { + var isValid = isValidIdentifier(str); + if (!isValid) { + throw new Error('invalid identifier: ' + str); + } + return str; +}; + +function isValidClassName(str) { + if (!str) { + return false; + } + + var arr = str.split('.'); + var len = arr.length; + for (var i = 0; i < len; i++) { + if (!isValidIdentifier(arr[i])) { + return false; + } + } + return true; +} + +exports.isValidClassName = isValidClassName; +exports.ensureValidClassName = function ensureValidClassName(str) { + var isValid = isValidClassName(str); + if (!isValid) { + throw new Error('invalid className: ' + str); + } + return str; +}; diff --git a/lib/v2/decoder.js b/lib/v2/decoder.js index 179bfe7..3706c46 100644 --- a/lib/v2/decoder.js +++ b/lib/v2/decoder.js @@ -483,7 +483,7 @@ proto._readObjectDefinition = function () { var gen = codegen(['decoder', 'withType'], 'decode'); gen('// %s', cachekey); gen('var result = {'); - gen(' $class: \'%s\',', classname); + gen(' $class: \'%s\',', utils.ensureValidClassName(classname)); gen(' $: {'); for (var field of fields) { if (errorProps[field]) { @@ -492,7 +492,7 @@ proto._readObjectDefinition = function () { if (INNER_CLASS_LABEL === field) { continue; } - gen(' %s: null,', field); + gen(' %s: null,', utils.ensureValidIdentifier(field)); } gen(' },'); gen('};'); @@ -501,7 +501,7 @@ proto._readObjectDefinition = function () { if (INNER_CLASS_LABEL === field) { gen('decoder.read(false);'); } else { - gen('result.$.%s = decoder.read(withType);', field); + gen('result.$.%s = decoder.read(withType);', utils.ensureValidIdentifier(field)); } } if (errorPropCount === 2) { diff --git a/test/special_cases.test.js b/test/special_cases.test.js index 961497f..c9cf41f 100644 --- a/test/special_cases.test.js +++ b/test/special_cases.test.js @@ -1,7 +1,8 @@ 'use strict'; -const hessian = require('../'); const assert = require('assert'); +const hessian = require('../'); +const ensureValidIdentifier = require('../lib/utils').ensureValidIdentifier; describe('test/special_cases.test', function() { it('should encode map like object in version: 1.0', function() { @@ -71,4 +72,21 @@ describe('test/special_cases.test', function() { }, }); }); + + describe('v2', () => { + it('should check class name', function () { + var buf = Buffer.from('4fa5313233272d636f6e736f6c652e6c6f672831292d27906f9070692e6d6f64656c2e53756273637269626572526567526573756c749806726573756c74076d657373616765047a6f6e65066461746149640770726f66696c6504757569640a696e7374616e636549640a617474726962757465736f90544e05475a30304253006f416c697061792e416e745669702d4a617661436c69656e743a6e616d653d636f6d2e616c697061792e616e747669702e636c69656e742e696e7465726e616c2e64726d2e44726d436f6e74726f6c2e726573747261696e53747261746567792c76657273696f6e3d332e304044524d4e53002465623334346332352d333234332d343265392d396162322d3364393462646533656239354e4d7a', 'hex'); + const classCache = new Map(); + classCache.enableCompile = true; + assert.throws(function () { + hessian.decode(buf, '2.0', { classCache }); + }, /invalid className/); + }); + + it('should throw error if invalid id', function () { + assert.throws(function () { + ensureValidIdentifier('a+c'); + }, /invalid identifier\: a\+c/); + }); + }); });