UNPKG

@atomist/sdm

Version:

Atomist Software Delivery Machine SDK

101 lines 4.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.wrapEventHandlersToVerifySignature = exports.EventSigningAutomationEventListener = void 0; const metadataReading_1 = require("@atomist/automation-client/lib/internal/metadata/metadataReading"); const constructionUtils_1 = require("@atomist/automation-client/lib/util/constructionUtils"); const logger_1 = require("@atomist/automation-client/lib/util/logger"); const crypto = require("crypto"); const _ = require("lodash"); const array_1 = require("../util/misc/array"); /** * AutomationEventListener that signs outgoing custom events with a configurable * JWS signature key. */ class EventSigningAutomationEventListener { constructor(esc) { this.esc = esc; this.initVerificationKeys(); } async onMutation(options) { if (eventMatch(options.name, this.esc.events)) { const privateKey = crypto.createPrivateKey({ key: this.esc.signingKey.privateKey, passphrase: this.esc.signingKey.passphrase, }); const { default: CompactSign } = require("jose/jws/compact/sign"); for (const key of Object.getOwnPropertyNames(options.variables || {})) { const value = options.variables[key]; const jws = await new CompactSign(Buffer.from(JSON.stringify(value))) .setProtectedHeader({ alg: "ES512" }) .sign(privateKey); value.signature = jws; logger_1.logger.debug(`Signed custom event '${options.name}'`); } } return options; } initVerificationKeys() { this.esc.verificationKeys = array_1.toArray(this.esc.verificationKeys) || []; // If signing key is set, also use it to verify if (!!this.esc.signingKey) { this.esc.verificationKeys.push(this.esc.signingKey); } } } exports.EventSigningAutomationEventListener = EventSigningAutomationEventListener; /** * Wrap every event handler that is registered and its subscription name matches a configurable set of * regular expression patterns for event signature verification. */ function wrapEventHandlersToVerifySignature(handlers, options) { const wh = []; for (const handler of handlers) { const instance = constructionUtils_1.toFactory(handler)(); const md = metadataReading_1.metadataFromInstance(instance); if (eventMatch(md.subscriptionName, options.events)) { wh.push(() => (Object.assign(Object.assign({}, md), { handle: async (e, ctx, params) => { const { default: compactVerify } = require("jose/jws/compact/verify"); for (const key of Object.getOwnPropertyNames(e.data)) { const evv = e.data[key][0]; if (!evv.signature) { throw new Error("Signature missing on incoming event"); } let verified = false; for (const pkey of array_1.toArray(options.verificationKeys)) { const publicKey = crypto.createPublicKey({ key: pkey.publicKey, }); try { const { payload } = await compactVerify(evv.signature, publicKey); e.data[key][0] = _.merge({}, evv, JSON.parse(Buffer.from(payload).toString())); verified = true; logger_1.logger.debug(`Verified signature on custom event '${md.subscriptionName}'`); break; } catch (e) { // return undefined; } } if (!verified) { throw new Error("Signature verification failed for incoming event"); } } return instance.handle(e, ctx, params); } }))); } else { wh.push(handler); } } return wh; } exports.wrapEventHandlersToVerifySignature = wrapEventHandlersToVerifySignature; function eventMatch(event, patterns) { for (const pattern of patterns) { if (new RegExp(pattern).test(event)) { return true; } } return false; } //# sourceMappingURL=eventSigning.js.map