Skip to content

Commit

Permalink
Merge pull request #471 from EasyPost/fix_webhook_validation_floats
Browse files Browse the repository at this point in the history
fix: webhook validation when float weight field is present (closes #467)
  • Loading branch information
Justintime50 committed Aug 16, 2024
2 parents 2304d1e + 615361c commit 21d5f90
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 14 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGELOG

## Next Release

- Fixes webhook validation when the `weight` field contains a float by converting it back into a float after conversion from a string (closes #467)

## v7.5.1 (2024-08-09)

- Adds missing properties to `Rate` model
Expand Down
9 changes: 7 additions & 2 deletions src/utils/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,14 @@ export default class Utils {
const normalizedSecret = webhookSecret.normalize('NFKD');
const encodedSecret = Buffer.from(normalizedSecret, 'utf8');

// Fixes Javascript's float to string conversion. See https://github.com/EasyPost/easypost-node/issues/467
const correctedEventBody = Buffer.from(eventBody)
.toString('utf8')
.replace(/("weight":\s*)(\d+)(\s*)(?=,|\})/g, '$1$2.0');

const expectedSignature = crypto
.createHmac('sha256', encodedSecret)
.update(eventBody, 'utf-8')
.update(correctedEventBody, 'utf-8')
.digest('hex');

const digest = `hmac-sha256-hex=${expectedSignature}`;
Expand All @@ -134,7 +139,7 @@ export default class Utils {
Buffer.from(digest, 'utf8'),
)
) {
webhook = JSON.parse(eventBody.toString());
webhook = JSON.parse(correctedEventBody);
} else {
throw new SignatureVerificationError({ message: Constants.WEBHOOK_DOES_NOT_MATCH });
}
Expand Down
16 changes: 12 additions & 4 deletions test/helpers/fixture.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ export default class Fixture {
return '2022-04-11';
}

static webhookUrl() {
return this.readFixtureData().webhook_url;
}

static caAddress1() {
return this.readFixtureData().addresses.ca_address_1;
}
Expand Down Expand Up @@ -143,6 +139,18 @@ export default class Fixture {
return Buffer.from(JSON.stringify(eventBody), 'utf8');
}

static webhookHmacSignature() {
return this.readFixtureData().webhook_hmac_signature;
}

static webhookSecret() {
return this.readFixtureData().webhook_secret;
}

static webhookUrl() {
return this.readFixtureData().webhook_url;
}

static plannedShipDate() {
return '2024-08-01';
}
Expand Down
12 changes: 5 additions & 7 deletions test/services/webhook.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { expect } from 'chai';

import EasyPostClient from '../../src/easypost';
import SignatureVerificationError from '../../src/errors/general/signature_verification_error';
import Webhook from '../../src/models/webhook';
import Fixture from '../helpers/fixture';
import SignatureVerificationError from '../../src/errors/general/signature_verification_error';
import * as setupPolly from '../helpers/setup_polly';
import { withoutParams } from '../helpers/utils';

Expand Down Expand Up @@ -87,20 +87,18 @@ describe('Webhook Service', function () {
});

it('validates a webhook secret', function () {
const webhookSecret = 'sécret';
const expectedHmacSignature =
'hmac-sha256-hex=e93977c8ccb20363d51a62b3fe1fc402b7829be1152da9e88cf9e8d07115a46b';
const headers = {
'X-Hmac-Signature': expectedHmacSignature,
'X-Hmac-Signature': Fixture.webhookHmacSignature(),
};

const webhookBody = this.client.Utils.validateWebhook(
Fixture.eventBody(),
headers,
webhookSecret,
Fixture.webhookSecret(),
);

expect(webhookBody.description).to.equal('batch.created');
expect(webhookBody.description).to.equal('tracker.updated');
expect(webhookBody.result.weight).to.equal(614.4); // Ensure we convert floats properly
});

it('throws an error when a webhook secret is a differing length', function () {
Expand Down

0 comments on commit 21d5f90

Please sign in to comment.