Business-TrueLayer
view release on metacpan or search on metacpan
t/business/truelayer/webhook.t view on Meta::CPAN
#!perl
use strict;
use warnings;
use Test::Most;
use Test::Warnings;
use Mojo::JWT;
use Mojo::JSON;
use Crypt::OpenSSL::RSA;
use_ok( 'Business::TrueLayer::Webhook' );
# generate a JWT we can use for testing - we can't use anything from
# TrueLayer as we a) don't know their private key for signing the JWT,
# and b) can't be sure the the details from the jwks will not change
my $private_key = "-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDLy/mVwBQmT76UNIilJd+d3t0SxjMWDthb77WgfNZ2f3/TxhUH
re3Mr/AgNSTzXz8GQSuWwgY9HwiDcp6c6eHnQWY/mF0/ig3BDDHIWjySaFc09Kfb
V4sWpte5KhS3M+FTzMtbdfZtp48R0wp8HHnduKchlrh6Vt+fNCdlXCzBYwIDAQAB
AoGAL9eFkvMRh+Dmk3I1tddLRItiCJtAuOfpQMPoNnG4Av9xaayxmSjqj0eqLlVr
hDqS2AwKiIyp3EVhwUHyHFIHdtAp/DhLMNymA6cOYZ+pSIQyF+1e/Q7KsitKrQht
YHzjC8P7lWMK5nfzrSEz9ykRtqO0yRMUJ+E12I4O/xkgV4kCQQDq0qGaSHl/cYcI
ibQJEUbHGhOscsSg61MmbsSQt2pfMPo7oP1fPaYcysLRmbg+ZTx8YfDDMR6R+CDX
uVl2D6udAkEA3i0LXB8JolUBEoxle/e59X3SmjVqFNMp/ClA9NeRttyiMsesCOf6
OouEMBAiDAZKlgznFPfoyJYQOakdSQMQ/wJBANKrXWg5FSeNBoRWZjqsUT9W2ceg
v19PQC3+ukLLCpeULStJ54aGnHzAO8AnlPAFixpcE9BKRQ7X+T8Qfn442NECQEwT
roUf16OvacuZKZL2c8W9DOVjDu0MlZ7T3Xs5aZrtF9k9iAoQrR1o8p2mmJH3gYi5
6FLExQASaoHkB7Qdia8CQQCXHtxHmBiNR1CF6qTGjhCPChPidvmhXNtDShHM3Gi7
yY9KhOLcT4W0YyXCCoEjG0bzu4OtK5ukhic86BYvbfYV
-----END RSA PRIVATE KEY-----";
my $public_key = "-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAMvL+ZXAFCZPvpQ0iKUl353e3RLGMxYO2FvvtaB81nZ/f9PGFQet7cyv
8CA1JPNfPwZBK5bCBj0fCINynpzp4edBZj+YXT+KDcEMMchaPJJoVzT0p9tXixam
17kqFLcz4VPMy1t19m2njxHTCnwced24pyGWuHpW3580J2VcLMFjAgMBAAE=
-----END RSA PUBLIC KEY-----";
my $jwkset = [
{
"kty" => "RSA",
"alg" => "RS512",
"kid" => "3f1266344cc2e6c2d8ede78240de88",
"n" => "y8v5lcAUJk--lDSIpSXfnd7dEsYzFg7YW--1oHzWdn9_08YVB63tzK_wIDUk818_BkErlsIGPR8Ig3KenOnh50FmP5hdP4oNwQwxyFo8kmhXNPSn21eLFqbXuSoUtzPhU8zLW3X2baePEdMKfBx53binIZa4elbfnzQnZVwswWM",
"e" => "AQAB",
}
];
my %payload = (
algorithm => 'RS512',
header => {
kid => "3f1266344cc2e6c2d8ede78240de88",
jku => 'https://webhooks.truelayer-sandbox.com/.well-known/jwks',
},
claims => {
"type" => "mandate_authorized",
"event_version" => 1,
"authorized_at" => "2024-08-23T07:26:33Z"
},
secret => $private_key,
);
my $jwt = Mojo::JWT->new( %payload )->encode;
my $Webhook = Business::TrueLayer::Webhook->new({
jwks => $jwkset,
jwt => $jwt,
});
isa_ok( $Webhook,'Business::TrueLayer::Webhook','with jwks' );
subtest 'no jwks provided' => sub {
no warnings qw/ redefine once /;
local *Mojo::UserAgent::get = sub { return $_[0] };
local *Mojo::UserAgent::result = sub { return $_[0] };
local *Mojo::UserAgent::json = sub { return { keys => $jwkset } };
$Webhook = Business::TrueLayer::Webhook->new({ jwt => $jwt });
isa_ok( $Webhook,'Business::TrueLayer::Webhook','without jwks' );
cmp_deeply(
$Webhook->_payload,
{
'authorized_at' => '2024-08-23T07:26:33Z',
'event_version' => 1,
'type' => 'mandate_authorized'
},
'->_payload'
);
subtest 'with unknown jku' => sub {
$payload{header}{jku} = 'https://some.man.in.the.middle.com';
$jwt = Mojo::JWT->new( %payload )->encode;
throws_ok(
sub { Business::TrueLayer::Webhook->new({ jwt => $jwt }) },
qr/is not in the jku_accept_list/,
'throws meaningful error'
);
};
};
subtest '_payload' => sub {
# https://docs.truelayer.com/docs/mandate-webhooks
$Webhook->_payload({
'type' => 'mandate_authorized',
'event_id' => 'SOMEUUID',
'event_version' => 1,
'mandate_id' => '123456',
'authorized_at' => '2024-08-23T07:26:33Z',
'metadata' => {},
});
ok( ! $Webhook->is_payment,'! ->is_payment' );
ok( $Webhook->is_mandate,'->is_mandate' );
( run in 0.616 second using v1.01-cache-2.11-cpan-364913b4093 )