From 1c89b4e2f18136e57356be262fe2997921d25602 Mon Sep 17 00:00:00 2001 From: Lance Ball Date: Wed, 22 Jun 2022 13:23:10 -0400 Subject: [PATCH 1/2] fix: improve validation on extension attribute Fixes: https://github.com/cloudevents/sdk-javascript/issues/500 Adds a regular expression check to the attribute name validation code to ensure that attribute names only use a-z0-9 (except for `data_base64`, which apparently is an exception to the rule. Signed-off-by: Lance Ball --- src/event/spec.ts | 7 ++++--- test/integration/kafka_tests.ts | 2 +- test/integration/message_test.ts | 25 +++++++++++++++++++++++-- test/integration/mqtt_tests.ts | 2 +- test/integration/spec_1_tests.ts | 10 ++++++++++ 5 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/event/spec.ts b/src/event/spec.ts index 25def7df..bfab4f3d 100644 --- a/src/event/spec.ts +++ b/src/event/spec.ts @@ -18,10 +18,11 @@ export function validateCloudEvent(event: CloudEventV1): boolean { } else { return false; } - // attribute names must all be lowercase + // attribute names must all be [a-z|0-9] + const validation = /^[a-z0-9]+$/; for (const key in event) { - if (key !== key.toLowerCase()) { - throw new ValidationError(`invalid attribute name: ${key}`); + if (validation.test(key) === false && key !== "data_base64") { + throw new ValidationError(`invalid attribute name: "${key}"`); } } return true; diff --git a/test/integration/kafka_tests.ts b/test/integration/kafka_tests.ts index 8870d479..ac0e0c47 100644 --- a/test/integration/kafka_tests.ts +++ b/test/integration/kafka_tests.ts @@ -131,7 +131,7 @@ describe("Kafka transport", () => { expect(event.LUNCH).to.equal("tacos"); expect(function () { event.validate(); - }).to.throw("invalid attribute name: LUNCH"); + }).to.throw("invalid attribute name: \"LUNCH\""); }); it("Can detect CloudEvent binary Messages with weird versions", () => { diff --git a/test/integration/message_test.ts b/test/integration/message_test.ts index b1afad4b..4589cc49 100644 --- a/test/integration/message_test.ts +++ b/test/integration/message_test.ts @@ -41,7 +41,28 @@ const imageData = new Uint32Array(fs.readFileSync(path.join(process.cwd(), "test const image_base64 = asBase64(imageData); describe("HTTP transport", () => { - + it("validates extension attribute names for incoming messages", () => { + // create a new Message + const msg: Message = { + headers: { + "ce-id": "213", + "ce-source": "test", + "ce-type": "test", + "ce-bad-extension": "value" + }, + body: undefined + }; + const evt = HTTP.toEvent(msg) as CloudEvent; + // expect(evt.validate).to.throw(TypeError); + try { + evt.validate(); + console.error(evt); + // fail("Should ahve thrown"); + } catch(err) { + console.error(err); + } + }); + it("Includes extensions in binary mode when type is 'boolean' with a false value", () => { const evt = new CloudEvent({ source: "test", type: "test", extboolean: false }); expect(evt.hasOwnProperty("extboolean")).to.equal(true); @@ -129,7 +150,7 @@ describe("HTTP transport", () => { expect(event.LUNCH).to.equal("tacos"); expect(function () { event.validate(); - }).to.throw("invalid attribute name: LUNCH"); + }).to.throw("invalid attribute name: \"LUNCH\""); }); it("Can detect CloudEvent binary Messages with weird versions", () => { diff --git a/test/integration/mqtt_tests.ts b/test/integration/mqtt_tests.ts index 411a9cd7..69b77e52 100644 --- a/test/integration/mqtt_tests.ts +++ b/test/integration/mqtt_tests.ts @@ -134,7 +134,7 @@ describe("MQTT transport", () => { expect(event.LUNCH).to.equal("tacos"); expect(function () { event.validate(); - }).to.throw("invalid attribute name: LUNCH"); + }).to.throw("invalid attribute name: \"LUNCH\""); }); it("Can detect CloudEvent binary Messages with weird versions", () => { diff --git a/test/integration/spec_1_tests.ts b/test/integration/spec_1_tests.ts index 7bd22483..9759d8fc 100644 --- a/test/integration/spec_1_tests.ts +++ b/test/integration/spec_1_tests.ts @@ -99,6 +99,16 @@ describe("CloudEvents Spec v1.0", () => { it("should be ok when the type is an string converted from an object", () => { expect(cloudevent.cloneWith({ objectextension: JSON.stringify({ some: "object" }) }).validate()).to.equal(true); }); + + it("should only allow a-z|0-9 in the attribute names", () => { + const testCases = [ + "an extension", "an_extension", "an-extension", "an.extension", "an+extension" + ]; + testCases.forEach((testCase) => { + const evt = cloudevent.cloneWith({ [testCase]: "a value"}, false); + expect(() => evt.validate()).to.throw(ValidationError); + }); + }); }); describe("The Constraints check", () => { From ba70a9a3a1f8a458b47020defffa6a63cdc02fc6 Mon Sep 17 00:00:00 2001 From: Lance Ball Date: Wed, 22 Jun 2022 13:28:53 -0400 Subject: [PATCH 2/2] fixup Signed-off-by: Lance Ball --- test/integration/message_test.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/test/integration/message_test.ts b/test/integration/message_test.ts index 4589cc49..46ab21f0 100644 --- a/test/integration/message_test.ts +++ b/test/integration/message_test.ts @@ -53,14 +53,7 @@ describe("HTTP transport", () => { body: undefined }; const evt = HTTP.toEvent(msg) as CloudEvent; - // expect(evt.validate).to.throw(TypeError); - try { - evt.validate(); - console.error(evt); - // fail("Should ahve thrown"); - } catch(err) { - console.error(err); - } + expect(() => evt.validate()).to.throw(TypeError); }); it("Includes extensions in binary mode when type is 'boolean' with a false value", () => {