File Coverage

blib/lib/Business/GoCardless/Webhook/V2.pm
Criterion Covered Total %
statement 22 22 100.0
branch n/a
condition n/a
subroutine 8 8 100.0
pod 1 1 100.0
total 31 31 100.0


line stmt bran cond sub pod time code
1             package Business::GoCardless::Webhook::V2;
2              
3             =head1 NAME
4              
5             Business::GoCardless::Webhook
6              
7             =head1 DESCRIPTION
8              
9             A class for gocardless webhooks, extends L.
10             For more details see the gocardless API documentation specific to webhooks:
11             https://developer.gocardless.com/api-reference/#appendix-webhooks
12              
13             Note to use webhooks you must set the webhook_secret on the client object
14              
15             =cut
16              
17 3     3   807 use strict;
  3         10  
  3         88  
18 3     3   21 use warnings;
  3         7  
  3         72  
19              
20 3     3   22 use Moo;
  3         25  
  3         22  
21             extends 'Business::GoCardless::Webhook';
22             with 'Business::GoCardless::Utils';
23              
24 3     3   1228 use JSON ();
  3         9  
  3         58  
25 3     3   985 use Business::GoCardless::Client;
  3         13  
  3         129  
26 3     3   24 use Business::GoCardless::Exception;
  3         7  
  3         115  
27 3     3   1466 use Business::GoCardless::Webhook::Event;
  3         9  
  3         1262  
28              
29             =head1 ATTRIBUTES
30              
31             json
32             signature
33             has_legacy_data
34              
35             =cut
36              
37             has [ qw/
38             events
39             signature
40             _signature
41              
42             has_legacy_data
43             legacy_webhook
44             / ] => (
45             is => 'rw',
46             clearer => 1,
47             );
48              
49             =head1 Operations on a webhook
50              
51             =head2 events
52              
53             Get a list of L objects for processing:
54              
55             foreach my $Event ( @{ $Webhook->events // [] } ) {
56             ...
57             }
58              
59             =head2 json
60              
61             Allows you to set the json data sent to you in the webhook:
62              
63             $Webhook->json( $json_data )
64              
65             Will throw a L exception if the json fails to
66             parse or if the signature does not match the payload data.
67              
68             =cut
69              
70             has json => (
71             is => 'rw',
72             required => 1,
73             trigger => sub {
74             my ( $self,$json ) = @_;
75              
76             # defensive decoding
77             my $params;
78             eval { $params = JSON->new->decode( $json ) };
79             $@ && do {
80             $self->clear_events;
81             $self->clear_signature;
82              
83             Business::GoCardless::Exception->throw({
84             message => "Failed to parse json: $@",
85             });
86             };
87              
88             if ( $params->{payload} ) {
89              
90             # this is a legacy API webhook
91             $self->has_legacy_data( 1 );
92              
93             my $LegacyWebhook = Business::GoCardless::Webhook->new(
94             json => $json,
95             client => Business::GoCardless::Client->new(
96             app_secret => $self->client->webhook_secret, # bad assumption?
97             %{ $self->client },
98             ),
99             );
100              
101             $self->legacy_webhook( $LegacyWebhook );
102              
103             } else {
104              
105             # coerce the events into objects
106             $self->events([
107             map { Business::GoCardless::Webhook::Event->new(
108             client => $self->client,
109             %{ $_ }
110             ) }
111             @{ $params->{events} }
112             ]);
113              
114             $self->signature( $self->_signature ) if ! $self->signature;
115              
116             if ( ! $self->signature_valid(
117             $json,$self->client->webhook_secret,$self->signature
118             ) ) {
119             $self->clear_events;
120             $self->clear_signature;
121              
122             Business::GoCardless::Exception->throw({
123             message => "Invalid signature for webhook",
124             });
125             }
126             }
127              
128             return $json;
129             }
130             );
131              
132             =head2 is_legacy
133              
134             See if the webhook is a legacy (Basic API) webhook
135              
136             if ( $Webhook->is_legacy ) {
137             ...
138             }
139              
140             =cut
141              
142 1     1 1 815 sub is_legacy { 0 }
143              
144             =head1 CONFIRMING WEBHOOKS
145              
146             According to the gocardless API docs you should respond once the signature of the
147             webhook has been checked. The response is a HTTP status 204 code:
148              
149             HTTP/1.1 204 OK
150              
151             You should handle this in your own code, the library will not do it for you. See
152             https://developer.gocardless.com/#response for more information
153              
154             =head1 AUTHOR
155              
156             Lee Johnson - C
157              
158             This library is free software; you can redistribute it and/or modify it under
159             the same terms as Perl itself. If you would like to contribute documentation,
160             features, bug fixes, or anything else then please raise an issue / pull request:
161              
162             https://github.com/Humanstate/business-gocardless
163              
164             =cut
165              
166             1;
167              
168             # vim: ts=4:sw=4:et