diff --git a/src/event/cloudevent.ts b/src/event/cloudevent.ts index ecacbfb..93516e2 100644 --- a/src/event/cloudevent.ts +++ b/src/event/cloudevent.ts @@ -96,6 +96,11 @@ export class CloudEvent implements CloudEventV1, CloudEventV03 { // finally process any remaining properties - these are extensions for (const [key, value] of Object.entries(properties)) { + // Extension names should only allow lowercase a-z and 0-9 in the name + // names should not exceed 20 characters in length + if (!key.match(/^[a-z0-9]{1,20}$/)) { + throw new ValidationError("invalid extension name"); + } this[key] = value; } diff --git a/test/integration/cloud_event_test.ts b/test/integration/cloud_event_test.ts index 6ea0645..8a98a62 100644 --- a/test/integration/cloud_event_test.ts +++ b/test/integration/cloud_event_test.ts @@ -25,6 +25,18 @@ describe("A CloudEvent", () => { const ce = new CloudEvent(fixture); expect(ce.toString()).to.deep.equal(JSON.stringify(ce)); }); + + it("Throw a validation error for invalid extension names", () => { + expect(() => { + new CloudEvent({ "ext-1": "extension1", ...fixture }); + }).throw("invalid extension name"); + }); + + it("Throw a validation error for invalid extension names, more than 20 chars", () => { + expect(() => { + new CloudEvent({ "123456789012345678901": "extension1", ...fixture }); + }).throw("invalid extension name"); + }); }); describe("A 1.0 CloudEvent", () => { @@ -92,13 +104,13 @@ describe("A 1.0 CloudEvent", () => { it("can be constructed with extensions", () => { const extensions = { - "extension-key": "extension-value", + extensionkey: "extension-value", }; const ce = new CloudEvent({ ...extensions, ...fixture, }); - expect(ce["extension-key"]).to.equal(extensions["extension-key"]); + expect(ce["extensionkey"]).to.equal(extensions["extensionkey"]); }); it("throws ValidationError if the CloudEvent does not conform to the schema"); diff --git a/test/integration/receiver_structured_1_test.ts b/test/integration/receiver_structured_1_test.ts index 6e36809..250dab9 100644 --- a/test/integration/receiver_structured_1_test.ts +++ b/test/integration/receiver_structured_1_test.ts @@ -11,8 +11,6 @@ const source = "urn:event:from:myapi/resourse/123"; const time = new Date(); const dataschema = "http://cloudevents.io/schema.json"; -const ceContentType = "application/json"; - const data = { foo: "bar", }; @@ -108,7 +106,6 @@ describe("HTTP Transport Binding Structured Receiver for CloudEvents v1.0", () = time, data, dataschema, - dataContentType: ceContentType, }; const headers = { "content-type": "application/cloudevents+json", @@ -124,14 +121,13 @@ describe("HTTP Transport Binding Structured Receiver for CloudEvents v1.0", () = it("Should accept 'extension1'", () => { // setup - const extension1 = "mycustom-ext1"; + const extension1 = "mycustomext1"; const event = { type, source, time, data, dataschema, - dataContentType: ceContentType, extension1, }; @@ -152,7 +148,6 @@ describe("HTTP Transport Binding Structured Receiver for CloudEvents v1.0", () = time, dataschema, data: data, - dataContentType: ceContentType, }; const headers = { @@ -173,7 +168,6 @@ describe("HTTP Transport Binding Structured Receiver for CloudEvents v1.0", () = type, source, data: bindata, - dataContentType: ceContentType, }; const headers = { diff --git a/test/integration/spec_1_tests.ts b/test/integration/spec_1_tests.ts index 47dd1b5..d580283 100644 --- a/test/integration/spec_1_tests.ts +++ b/test/integration/spec_1_tests.ts @@ -65,26 +65,26 @@ describe("CloudEvents Spec v1.0", () => { describe("Extensions Constraints", () => { it("should be ok when type is 'boolean'", () => { - expect(cloudevent.cloneWith({ "ext-boolean": true }).validate()).to.equal(true); + expect(cloudevent.cloneWith({ extboolean: true }).validate()).to.equal(true); }); it("should be ok when type is 'integer'", () => { - expect(cloudevent.cloneWith({ "ext-integer": 2019 }).validate()).to.equal(true); + expect(cloudevent.cloneWith({ extinteger: 2019 }).validate()).to.equal(true); }); it("should be ok when type is 'string'", () => { - expect(cloudevent.cloneWith({ "ext-string": "an-string" }).validate()).to.equal(true); + expect(cloudevent.cloneWith({ extstring: "an-string" }).validate()).to.equal(true); }); it("should be ok when type is 'Uint32Array' for 'Binary'", () => { const myBinary = new Uint32Array(2019); - expect(cloudevent.cloneWith({ "ext-binary": myBinary }).validate()).to.equal(true); + expect(cloudevent.cloneWith({ extbinary: myBinary }).validate()).to.equal(true); }); // URI it("should be ok when type is 'Date' for 'Timestamp'", () => { const myDate = new Date(); - expect(cloudevent.cloneWith({ "ext-date": myDate }).validate()).to.equal(true); + expect(cloudevent.cloneWith({ extdate: myDate }).validate()).to.equal(true); }); // even though the spec doesn't allow object types for @@ -92,7 +92,7 @@ describe("CloudEvents Spec v1.0", () => { // is transmitted across the wire, this value will be // converted to JSON it("should be ok when the type is an object", () => { - expect(cloudevent.cloneWith({ "object-extension": { some: "object" } }).validate()).to.equal(true); + expect(cloudevent.cloneWith({ objectextension: { some: "object" } }).validate()).to.equal(true); }); });