fix: support mTLS in 1.0 Binary and Structured emitters

This commit modifies both of the 1.0 emitters so that they may
accept typed objects as a part of the configuration. When using
mTLS in Node, you need to provide an `Agent` to the underlying
HTTP handler. In this case, Axios will pass this object along to
Node.js when it is provided.

Fixes: https://github.com/cloudevents/sdk-javascript/issues/48

Signed-off-by: Lance Ball <lball@redhat.com>
This commit is contained in:
Lance Ball 2020-04-08 16:13:57 -04:00
parent 4a199d4623
commit 3a063d7245
No known key found for this signature in database
GPG Key ID: DB1D2F8DCDB4EE5C
4 changed files with 72 additions and 57 deletions

View File

@ -2,58 +2,48 @@ var axios = require("axios");
var empty = require("is-empty");
const Constants = require("./constants.js");
const defaults = {};
defaults[Constants.HEADERS] = {};
defaults[Constants.HEADERS][Constants.HEADER_CONTENT_TYPE] = Constants.DEFAULT_CONTENT_TYPE;
function BinaryHTTPEmitter(config, headerByGetter, extensionPrefix){
this.config = JSON.parse(JSON.stringify(config));
this.config = Object.assign({}, defaults, config);
this.headerByGetter = headerByGetter;
this.extensionPrefix = extensionPrefix;
this.config[Constants.HEADERS] =
(!this.config[Constants.HEADERS]
? {}
: this.config[Constants.HEADERS]);
// default is json
if(!this.config[Constants.HEADERS][Constants.HEADER_CONTENT_TYPE]){
this.config[Constants.HEADERS][Constants.HEADER_CONTENT_TYPE] =
Constants.DEFAULT_CONTENT_TYPE;
}
}
BinaryHTTPEmitter.prototype.emit = function(cloudevent) {
// Create new request object
var _config = JSON.parse(JSON.stringify(this.config));
// Always set stuff in _config
var _headers = _config[Constants.HEADERS];
BinaryHTTPEmitter.prototype.emit = function (cloudevent) {
const config = Object.assign({}, this.config);
const headers = Object.assign({}, this.config[Constants.HEADERS]);
Object.keys(this.headerByGetter)
.filter((getter) => cloudevent[getter]())
.forEach((getter) => {
let header = this.headerByGetter[getter];
_headers[header.name] =
const header = this.headerByGetter[getter];
headers[header.name] =
header.parser(
cloudevent[getter]()
);
});
// Set the cloudevent payload
let formatted = cloudevent.format();
const formatted = cloudevent.format();
let data = formatted.data;
data = (formatted.data_base64 ? formatted.data_base64: data);
_config[Constants.DATA_ATTRIBUTE] = data;
// Have extensions?
var exts = cloudevent.getExtensions();
const exts = cloudevent.getExtensions();
Object.keys(exts)
.filter((ext) => Object.hasOwnProperty.call(exts, ext))
.forEach((ext) => {
_headers[this.extensionPrefix + ext] = exts[ext];
headers[this.extensionPrefix + ext] = exts[ext];
});
// Return the Promise
return axios.request(_config);
};
config[Constants.DATA_ATTRIBUTE] = data;
config.headers = headers;
// Return the Promise
return axios.request(config);
};
module.exports = BinaryHTTPEmitter;

View File

@ -1,30 +1,23 @@
var axios = require("axios");
const Constants = require("./constants.js");
const defaults = {};
defaults[Constants.HEADERS] = {};
defaults[Constants.HEADERS][Constants.HEADER_CONTENT_TYPE] = Constants.DEFAULT_CE_CONTENT_TYPE;
function StructuredHTTPEmitter(configuration){
this.config = JSON.parse(JSON.stringify(configuration));
this.config[Constants.HEADERS] =
(!this.config[Constants.HEADERS]
? {}
: this.config[Constants.HEADERS]);
if(!this.config[Constants.HEADERS][Constants.HEADER_CONTENT_TYPE]){
this.config[Constants.HEADERS][Constants.HEADER_CONTENT_TYPE] =
Constants.DEFAULT_CE_CONTENT_TYPE;
}
this.config = Object.assign({}, defaults, configuration);
}
StructuredHTTPEmitter.prototype.emit = function(cloudevent) {
// Create new request object
var _config = JSON.parse(JSON.stringify(this.config));
StructuredHTTPEmitter.prototype.emit = function (cloudevent) {
// Set the cloudevent payload
_config[Constants.DATA_ATTRIBUTE] = cloudevent.format();
this.config[Constants.DATA_ATTRIBUTE] = cloudevent.format();
// Return the Promise
return axios.request(_config);
return axios.request(this.config).then(response => {
delete this.config[Constants.DATA_ATTRIBUTE];
return response;
});
};
module.exports = StructuredHTTPEmitter;

View File

@ -1,14 +1,14 @@
const expect = require("chai").expect;
const nock = require("nock");
const http = require("http");
const request = require("request");
const https = require("https");
const {asBase64} = require("../lib/utils/fun.js");
const BinaryHTTPEmitter =
require("../lib/bindings/http/emitter_binary_1.js");
const Cloudevent = require("../lib/cloudevent.js");
const v1 = require("../v1/index.js");
const {
Spec,
BinaryHTTPEmitter,
StructuredHTTPEmitter,
Cloudevent
} = require("../v1/index.js");
const type = "com.github.pull.create";
const source = "urn:event:from:myapi/resourse/123";
@ -28,7 +28,7 @@ const ext2Name = "extension2";
const ext2Value = "acme";
const cloudevent =
new Cloudevent(v1.Spec)
new Cloudevent(Spec)
.type(type)
.source(source)
.dataContentType(ceContentType)
@ -48,7 +48,7 @@ const httpcfg = {
};
const binary = new BinaryHTTPEmitter(httpcfg);
const structured = new v1.StructuredHTTPEmitter(httpcfg);
const structured = new StructuredHTTPEmitter(httpcfg);
describe("HTTP Transport Binding - Version 1.0", () => {
beforeEach(() => {
@ -59,6 +59,21 @@ describe("HTTP Transport Binding - Version 1.0", () => {
});
describe("Structured", () => {
it('works with mTLS authentication', () => {
const event = new StructuredHTTPEmitter({
method: 'POST',
url: `${webhook}/json`,
httpsAgent: new https.Agent({
cert: 'some value',
key: 'other value'
})
})
return event.emit(cloudevent).then(response => {
expect(response.config.headers['Content-Type'])
.to.equal(contentType);
});
});
describe("JSON Format", () => {
it("requires '" + contentType + "' Content-Type in the header", () => {
return structured.emit(cloudevent)
@ -81,7 +96,7 @@ describe("HTTP Transport Binding - Version 1.0", () => {
let bindata = Uint32Array.from(dataString, (c) => c.codePointAt(0));
let expected = asBase64(bindata);
let binevent =
new Cloudevent(v1.Spec)
new Cloudevent(Spec)
.type(type)
.source(source)
.dataContentType("text/plain")
@ -98,7 +113,7 @@ describe("HTTP Transport Binding - Version 1.0", () => {
it("the payload must have 'data_base64' when data is binary", () => {
let binevent =
new Cloudevent(v1.Spec)
new Cloudevent(Spec)
.type(type)
.source(source)
.dataContentType("text/plain")
@ -117,6 +132,21 @@ describe("HTTP Transport Binding - Version 1.0", () => {
});
describe("Binary", () => {
it('works with mTLS authentication', () => {
const event = new BinaryHTTPEmitter({
method: 'POST',
url: `${webhook}/json`,
httpsAgent: new https.Agent({
cert: 'some value',
key: 'other value'
})
})
return event.emit(cloudevent).then(response => {
expect(response.config.headers['Content-Type'])
.to.equal(cloudevent.getDataContentType());
});
});
describe("JSON Format", () => {
it("requires '" + cloudevent.getDataContentType() + "' Content-Type in the header", () => {
return binary.emit(cloudevent)
@ -138,7 +168,7 @@ describe("HTTP Transport Binding - Version 1.0", () => {
let bindata = Uint32Array.from(dataString, (c) => c.codePointAt(0));
let expected = asBase64(bindata);
let binevent =
new Cloudevent(v1.Spec)
new Cloudevent(Spec)
.type(type)
.source(source)
.dataContentType("text/plain")

View File

@ -22,5 +22,7 @@ module.exports = {
BinaryHTTPEmitter,
StructuredHTTPReceiver,
BinaryHTTPReceiver,
Cloudevent: event,
CloudEvent: event,
event
};