HTTP-Request-Webpush

 view release on metacpan or  search on metacpan

examples/send.pl  view on Meta::CPAN

use warnings;

use HTTP::Request::Webpush;
use LWP::UserAgent;

my $server_key = { public => 'BCAI00zPAbxEVU5w8D1kZXVs2Ro--FmpQNMOd0S0w1_5naTLZTGTYNqIt7d97c2mUDstAWOCXkNKecqgS4jARA8',
   private => 'M6xy5prDBhJNlOGnOkMekyAQnQSWKuJj1cD06SUQTow'};

my $send=HTTP::Request::Webpush->new();

$send->subscription('{"endpoint":"https://bn3p.notify.windows.com/w/?token=BQYAAACgmmGJB%2fT6GgtS%2bZsefznjZgOG1kd2d05B80MIiQ%2fn5JKOOjrE7Bep8JYJoqRiAW67%2fyoq69DRfLFaZHxhBiYbWh6HfdUd0SbAAwe6%2fvk0ClM0a4%2bEfX0fzUflmVix%2fV8uM1lFqVidtOLLs20lnWw%2bH5N...
$send->subject('mailto:esf@moller.cl');
$send->authbase64($server_key->{public}, $server_key->{private});
$send->content("Billy Jean's not my lover");
$send->encode;
$send->header('TTL' => '90');

my $ua = LWP::UserAgent->new;
my $response = $ua->request($send);

print $response->code();

lib/HTTP/Request/Webpush.pm  view on Meta::CPAN


   my $agent;

   if (ref $subscription eq 'HASH') {
      $agent=$subscription;
   } else {
      eval {$agent=from_json($subscription); };
   }

   croak "Can't process subscription object" unless ($agent);
   croak "Subscription must include endpoint" unless (exists $agent->{endpoint});

   $self->uri($agent->{endpoint});
   $self->{subscription}=$agent;
   return $agent;
}

sub auth($@) {

   my $self=shift();

   if (scalar @_ == 2) {
      $self->{'app-pub'}=shift();

lib/HTTP/Request/Webpush.pm  view on Meta::CPAN

   #This method is inherited from HTTP::Message, but here only aes128gcm applies
   croak 'Only aes128gcm encoding available' unless ($enc eq 'aes128gcm');

   #Check prerequisites
   croak 'Endpoint must be present for message encoding' unless ($self->url());
   croak 'Authentication keys must be present for message encoding' unless ($self->{'app-key'});
   croak 'UA auth params must be present for message encoding' unless ($self->{subscription}->{'keys'}->{'p256dh'} && $self->{subscription}->{'keys'}->{'auth'});
   croak 'Message payload must be 3992 bytes or less' unless (length($self->content) <= 3992);

   #This is the JWT part
   my $origin=URI->new($self->{subscription}->{endpoint});
   $origin->path_query('');
   my $data={  
     'aud' => "$origin",
     'exp'=> time() + 86400  
   };
   $data->{'sub'}=$self->{'subject'} if ($self->{'subject'});
 
   my $appk = Crypt::PK::ECC->new();
   $appk->import_key_raw($self->{'app-key'},'secp256r1');
   my $token = encode_jwt(payload => $data, key => $appk  , alg=>'ES256');

lib/HTTP/Request/Webpush.pm  view on Meta::CPAN

   if ($self->{'ecc'}) {
      $pk=$self->{'ecc'};
   } else {
      $pk=Crypt::PK::ECC->new();
      $pk->generate_key('prime256v1');
   }

   my $pub_signkey=$pk->export_key_raw('public');
   my $sec_signkey=$pk->export_key_raw('private');

   my $sk=Crypt::PK::ECC->new(); #This will be the UA endpoint key, which we know from the subscription object

   #The p256dh key is given to us in X9.62 format. Crypt::PK::ECC should be able
   #to read it as a "raw" format. But it's important to apply the base64url variant
   my $ua_public=decode_base64url($self->{subscription}->{'keys'}->{'p256dh'});
   $sk->import_key_raw($ua_public, 'secp256r1');

   my $ecdh_secret=$pk->shared_secret($sk);
   my $auth_secret= decode_base64url($self->{subscription}->{'keys'}->{'auth'});

   #An earlier draft established this header string as Content-Encoding: auth

lib/HTTP/Request/Webpush.pm  view on Meta::CPAN

=head1 SYNOPSIS

 use HTTP::Request::Webpush;

 #This should be the application-wide VAPID key pair
 #The APP_PUB part must be the same used by the user UA when requesting the subscription
 use constant APP_PUB => 'BCAI...RA8';
 use constant APP_KEY => 'M6x...UQTow';
 
 #This should be previously collected from an already subscribed user UA
 my $subscription='{"endpoint":"https://foo/fooer","expirationTime":null,"keys":{"p256dh":"BCNS...","auth":"dZ..."}}';

 my $message=HTTP::Request::Webpush->new();
 $message->auth(APP_PUB, APP_KEY);
 $message->subscription($subscription);
 $message->subject('mailto:bobsbeverage@some.com');
 $message->content('Hello world');
 
 #Additional headers can be applied with inherited HTTP::Response methods
 $message->header('TTL' => '90');

lib/HTTP/Request/Webpush.pm  view on Meta::CPAN

=over 4

=item C<$r=HTTP::Request::Webpush-E<gt>new()>

=item C<$r=HTTP::Request::Webpush-E<gt>new(auth =E<gt> $my_key, subscription =E<gt> $my_subs, content='New lager batch arrived')>

The following options can be supplied in the constructor: subscription, auth, reuseecc, subject, content.

=item C<$r-E<gt>subscription($hash_reference)>

=item C<$r-E<gt>subscription('{"endpoint":"https://foo/fooer","expirationTime":null,"keys":{"p256dh":"BCNS...","auth":"dZ..."}}');>

This sets the subscription object related to this notification service. This should be the same object
returned inside the browser environment using the browser's Push API C<PushManager.subscribe()> method. The argument can
be either a JSON string or a previously setup hash reference. The HTTP::Request uri is taken verbatim from the endpoint
of the subscription object.

=item C<$r-E<gt>auth($pk) #pk being a Crypt::PK::ECC ref>

=item C<$r-E<gt>auth($pub_bin, $priv_bin)>

=item C<$r-E<gt>authbase64('BCAI...jARA8','M6...Tow')>

This sets the authentication key for the VAPID authentication scheme related to this push service.
This can either be a (public, private) pair or an already setup L<Crypt::PK::ECC> object. The public part

t/http-request-webpush-long.t  view on Meta::CPAN

   my $infoHmac= hmac_sha256($info,chr(1),$key);  

   return substr($infoHmac,0,$len);
}


#Basic stuff
BEGIN { use_ok('HTTP::Request::Webpush') };
my $send=new_ok( 'HTTP::Request::Webpush' );

#Now setup a dummy subscription endpoint
my $ua_publicKey= "BMj40clWPSKfZTdyaQQjFoEozKUXI3aEZDBFC_2dr0I5ZWX7bvahx3iDRJjbXf6t9FuSuuAq57cEb_R48lmVzPA";
my $ua_privateKey= "ibx1ebRZyWiWNB_fHXHmiLROYXDXD_II8EZ1nqef4VA";
my $auth=random_bytes(16);

my $app_publicKey= "BDIlKk-A0gBOnZ9DWHoEzSFe_HZbDEAY6yYgN6ILmdVC3mS8laszyLPI6FJhVXZpsJPSYlBkAyYrKRVBdD9fydY";
my $app_privateKey= "cLERT3eZx0JfS0pIX6orz_uGBzf1JV0I7PWGCaGfkbg";

my $service={"endpoint"=>"https://foo",
   "expirationTime" => 0,
   "keys"=> {
      "p256dh"=>$ua_publicKey,
      "auth"=> encode_base64url($auth)}};

ok($send->subscription($service) );
ok($send->authbase64($ua_publicKey,$ua_privateKey));


my $payload= <<'EOP';

t/http-request-webpush-reuse.t  view on Meta::CPAN

   my $infoHmac= hmac_sha256($info,chr(1),$key);  

   return substr($infoHmac,0,$len);
}


#Basic stuff
BEGIN { use_ok('HTTP::Request::Webpush') };
my $send=new_ok( 'HTTP::Request::Webpush' );

#Now setup a dummy subscription endpoint
my $ua_publicKey= "BMj40clWPSKfZTdyaQQjFoEozKUXI3aEZDBFC_2dr0I5ZWX7bvahx3iDRJjbXf6t9FuSuuAq57cEb_R48lmVzPA";
my $ua_privateKey= "ibx1ebRZyWiWNB_fHXHmiLROYXDXD_II8EZ1nqef4VA";
my $auth=random_bytes(16);

my $app_publicKey= "BDIlKk-A0gBOnZ9DWHoEzSFe_HZbDEAY6yYgN6ILmdVC3mS8laszyLPI6FJhVXZpsJPSYlBkAyYrKRVBdD9fydY";
my $app_privateKey= "cLERT3eZx0JfS0pIX6orz_uGBzf1JV0I7PWGCaGfkbg";

my $service={"endpoint"=>"https://foo",
   "expirationTime" => 0,
   "keys"=> {
      "p256dh"=>$ua_publicKey,
      "auth"=> encode_base64url($auth)}};

ok($send->subscription($service) );
ok($send->authbase64($ua_publicKey,$ua_privateKey));

my $reuse=Crypt::PK::ECC->new(); #For encryption
$reuse->generate_key('prime256v1');

t/http-request-webpush.t  view on Meta::CPAN

   my $infoHmac= hmac_sha256($info,chr(1),$key);  

   return substr($infoHmac,0,$len);
}


#Basic stuff
BEGIN { use_ok('HTTP::Request::Webpush') };
my $send=new_ok( 'HTTP::Request::Webpush' );

#Now setup a dummy subscription endpoint

my $ua_publicKey= "BMj40clWPSKfZTdyaQQjFoEozKUXI3aEZDBFC_2dr0I5ZWX7bvahx3iDRJjbXf6t9FuSuuAq57cEb_R48lmVzPA";
my $ua_privateKey= "ibx1ebRZyWiWNB_fHXHmiLROYXDXD_II8EZ1nqef4VA";
my $auth=random_bytes(16);

my $app_publicKey= "BDIlKk-A0gBOnZ9DWHoEzSFe_HZbDEAY6yYgN6ILmdVC3mS8laszyLPI6FJhVXZpsJPSYlBkAyYrKRVBdD9fydY";
my $app_privateKey= "cLERT3eZx0JfS0pIX6orz_uGBzf1JV0I7PWGCaGfkbg";

my $service={"endpoint"=>ENDPOINT,
   "expirationTime" => 0,
   "keys"=> {
      "p256dh"=>$ua_publicKey,
      "auth"=> encode_base64url($auth)}};

ok($send->subscription($service) , 'Can accept subscription data');
ok($send->authbase64($ua_publicKey,$ua_privateKey), 'Can accept auth data');

my $payload="Hello world";
$send->content($payload);



( run in 1.527 second using v1.01-cache-2.11-cpan-2b1a40005be )