Skip to content

Instantly share code, notes, and snippets.

@it-can
Last active September 18, 2024 21:10
Show Gist options
  • Save it-can/f237f84dd4e115b4628be10233f2c138 to your computer and use it in GitHub Desktop.
Save it-can/f237f84dd4e115b4628be10233f2c138 to your computer and use it in GitHub Desktop.
webhook validation mailpace laravel/php
<?php
// Retrieve the signature from the request headers and decode it from base64
$signature_base64 = $request->header('X-MailPace-Signature');
$signature = base64_decode($signature_base64);
if ($signature === false) {
// Invalid signature encoding
abort(400, 'Invalid signature encoding');
}
// Decode your public key from base64
$verify_key_base64 = 'Your Public Key from app.mailpace.com here';
$verify_key = base64_decode($verify_key_base64);
if ($verify_key === false) {
// Invalid public key encoding
abort(500, 'Invalid public key encoding');
}
// Retrieve the raw body of the request
$message = $request->getContent();
// Verify the signature
$isValid = sodium_crypto_sign_verify_detached($signature, $message, $verify_key);
if ($isValid) {
// Verification passed
return response('Verification passed', 200);
} else {
// Verification failed
abort(400, 'Invalid signature');
}
@it-can
Copy link
Author

it-can commented Sep 18, 2024

Ok will test it out thanks for now!

@it-can
Copy link
Author

it-can commented Sep 18, 2024

@paul-oms seems this is not working (the signature from the header) with strict set to true in base64_decode (https://www.php.net/base64_decode).

$message = '';

$signature = base64_decode("sHnRyHCzMpHhMrWT5\/GynEWzryRQG7FvWcCvvKHjDWV6r+\/X+OzG4YMpua78I7CYh+qC3hK9xXZlYHePZHopCg==", true);

$verify_key = base64_decode('private-key', true);

$isValid = sodium_crypto_sign_verify_detached($signature, $message, $verify_key);

this gives me an error:

sodium_crypto_sign_verify_detached(): Argument #1 ($signature) must be SODIUM_CRYPTO_SIGN_BYTES bytes long

EDIT:

seems not to happen on all signature headers... strange

EDIT2:
I removed the strict parameter from base64_decode, and it seems to work now

@paul-oms
Copy link

paul-oms commented Sep 18, 2024

strict decode should work on the signature. However I think I've found the root cause. It looks like Laravel (or something in the stack) automatically converts Unicode escape sequences when getContent() is called. So e.g. "message_id":"\[email protected]\u003e" is converted to "message_id":"<[email protected]>"

This won't match the original email we sign on our end, therefore preventing the signatures from matching - i'm checking for a way to get the original request without this

@paul-oms
Copy link

Looks like this should work:

$message = json_encode($response->getOriginalContent(), JSON_HEX_TAG);

Try that and let me know if you still face problems

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment