@fusebit-int/xero-connector
Version:
Xero Connector
57 lines • 2.85 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Service = void 0;
const crypto_1 = __importDefault(require("crypto"));
const superagent_1 = __importDefault(require("superagent"));
const oauth_connector_1 = require("@fusebit-int/oauth-connector");
class Service extends oauth_connector_1.OAuthConnector.Service {
getEventsFromPayload(ctx) {
return ctx.req.body.events;
}
getAuthIdFromEvent(ctx, event) {
return event.tenantId;
}
eventToString(event) {
return `{\n "resourceUrl": "${event.resourceUrl}",\n "resourceId": "${event.resourceId}",\n "eventDateUtc": "${event.eventDateUtc}",\n "eventType": "${event.eventType}",\n "eventCategory": "${event.eventCategory}",\n "tenantId": "${event.tenantId}",\n "tenantType": "${event.tenantType}"\n}`;
}
bodyToString(body) {
return `{"events":[${body.events.map((event) => this.eventToString(event)).join(',')}],"firstEventSequence": ${body.firstEventSequence},"lastEventSequence": ${body.lastEventSequence}, "entropy": "${body.entropy}"}`;
}
async validateWebhookEvent(ctx) {
const signingSecret = ctx.state.manager.config.configuration.signingSecret;
const requestSignature = ctx.req.headers['x-xero-signature'];
const body = ctx.req.body;
// Convert the body to a string:
const bodyString = this.bodyToString(body);
const calculatedSignature = crypto_1.default.createHmac('sha256', signingSecret).update(bodyString).digest('base64');
const calculatedSignatureBuffer = Buffer.from(calculatedSignature, 'utf8');
const requestSignatureBuffer = Buffer.from(requestSignature, 'utf8');
const result = crypto_1.default.timingSafeEqual(calculatedSignatureBuffer, requestSignatureBuffer);
// Xero has specific requirements about the return code: it must be 401, and there must be no body.
if (!result) {
ctx.throw(401, { hideBody: true });
}
return true;
}
async initializationChallenge(ctx) {
if (ctx.req.body.events.length === 0 && ctx.req.body.entropy) {
return true;
}
return false;
}
async getTokenAuthId(ctx, token) {
// Get the connections, which contains the list of tenants, and use those as ids.
const connections = await superagent_1.default
.get('https://api.xero.com/connections')
.set('Authorization', `Bearer ${token.access_token}`);
return connections.body.map((tenant) => tenant.tenantId);
}
getWebhookEventType(event) {
return event.eventType;
}
}
exports.Service = Service;
//# sourceMappingURL=Service.js.map