view release on metacpan or search on metacpan
NAME
Finance::Bank::Natwest - Check your Natwest bank accounts from Perl
DESCRIPTION
This module provides a rudimentary interface to the Natwest online
banking system at C<https://www.nwolb.com/>. You will need
either C<Crypt::SSLeay> or C<IO::Socket::SSL> installed for HTTPS
support to work with LWP.
SYNOPSIS
my $nw = Finance::Bank::Natwest->new( credentials => 'Constant',
credentials_options => {
dob => '010179',
uid => '0001',
password => 'Password',
pin => '4321' } );
my @accounts = $nw->accounts;
foreach (@accounts) {
printf "%25s : %6s / %8s : GBP %8.2f\n",
$_->{name}, $_->{sortcode}, $_->{account}, $_->{available};
lib/Finance/Bank/Natwest.pm view on Meta::CPAN
=head1 DESCRIPTION
This module provides a rudimentary interface to the Natwest online
banking system at C<https://www.nwolb.com/>. You will need
either C<Crypt::SSLeay> or C<IO::Socket::SSL> installed for HTTPS
support to work with LWP.
=head1 SYNOPSIS
my $nw = Finance::Bank::Natwest->new( credentials => 'Constant',
credentials_options => {
dob => '010179',
uid => '0001',
password => 'Password',
pin => '4321' } );
my @accounts = $nw->accounts;
foreach (@accounts) {
printf "%25s : %6s / %8s : GBP %8.2f\n",
$_->{name}, $_->{sortcode}, $_->{account}, $_->{available};
}
=head1 METHODS
=over 4
=item B<new>
my $nw = Finance::Bank::Natwest->new( credentials => 'Constant',
credentials_options => {
dob => '010179',
uid => '0001',
password => 'Password',
pin => '4321' }
);
# Or create the credentials object ourselves
my $credentials = Finance::Bank::Natwest::CredentialsProvider::Constant->new(
dob => '010179', uid => '0001', password => 'Password', pin => '4321' );
my $nw = Finance::Bank::Natwest->new( credentials => $credentials );
C<new> can be called in two different ways. It can take a single parameter,
C<credentials>, which will accept an already created credentials object, of type
C<Finance::Bank::Natwest::CredentialsProvider::*>. Alternatively, it can take two
parameters, C<credentials> and C<credentials_options>. In this case
C<credentials> is the name of a credentials class to create an instance of, and
C<credentials_options> is a hash of the options to pass-through to the
constructor of the chosen class.
If the second form of C<new> is being used, and the chosen class is I<not> one
of the ones supplied as standard then it will need to be C<required> first.
If any errors occur then C<new> will C<croak>.
=cut
use constant URL_ROOT => 'https://www.nwolb.com';
lib/Finance/Bank/Natwest.pm view on Meta::CPAN
};
=item B<accounts>
my @accounts = $nw->accounts;
# Or get a list ref instead
my $accounts = $nw->accounts;
Returns a list containing a summary of any accounts available from the
supplied credentials. Each item in the list is a hash reference that holds
summary information for a single account, and contains this data:
=over 4
=item B<name> - the name of the account
=item B<account> - the account number
=item B<sortcode>
lib/Finance/Bank/Natwest/Connection.pm view on Meta::CPAN
};
sub new{
my ($class, %opts) = @_;
my $self = bless {}, $class;
$self->{url_base} = $opts{url_base} || Finance::Bank::Natwest->url_base;
$self->_set_credentials( %opts );
$self->_new_ua( %opts );
return $self;
}
sub _new_ua{
my ($self, %opts) = @_;
my %proxy;
lib/Finance/Bank/Natwest/Connection.pm view on Meta::CPAN
keep_alive => 1,
timeout => 30,
cookie_jar => {},
requests_redirectable => [ 'GET', 'HEAD', 'POST' ],
agent => "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"
);
$self->{ua}->proxy('https', $proxy{proxy}) if exists $proxy{proxy};
}
sub _set_credentials{
my ($self, %opts) = @_;
croak "Must provide either a premade credentials object or ".
"a class name together with options, stopped" if
!exists $opts{credentials};
if (ref($opts{credentials})) {
croak "Can't accept credential options if supplying a premade ".
"credentials object, stopped" if
exists $opts{credentials_options};
croak "Not a valid credentials object, stopped" unless
$self->_isa_credentials($opts{credentials});
$self->{credentials} = $opts{credentials};
} else {
croak "Must provide credential options unless suppying a premade ".
"credentials object, stopped" if
!exists $opts{credentials_options};
$self->{credentials} =
$self->_new_credentials(
$opts{credentials}, $opts{credentials_options}
);
};
}
sub _new_credentials{
my ($self, $class, $options) = @_;
croak "Invalid class name, stopped" if
$class !~ /^(?:\w|::)+$/;
my $full_class = "Finance::Bank::Natwest::CredentialsProvider::$class";
eval "local \$SIG{'__DIE__'};
local \$SIG{'__WARN__'};
require $full_class;
";
croak "Not a valid credentials class, stopped"
if $@;
croak "Not a valid credentials class, stopped"
unless $self->_isa_credentials($full_class);
{
local $Carp::CarpLevel = $Carp::CarpLevel + 1;
return $full_class->new(%{$options});
}
}
sub _isa_credentials{
my ($self, $credentials) = @_;
my @required_subs = qw( new get_start get_stop get_identity get_pinpass );
foreach my $sub (@required_subs) {
return unless defined eval {
local $SIG{'__DIE__'};
local $SIG{'__WARN__'};
$credentials->can($sub);
};
}
return 1;
}
sub login{
my ($self) = @_;
my $page;
$self->{login_ok} = 0;
$self->{in_login} = 1;
delete $self->{rb_id};
$self->{credentials}->get_start();
my $identity = $self->{credentials}->get_identity();
($self->{rb_id}, $page) = $self->post( 'logon.asp',
{ DBIDa => $identity->{dob}, DBIDb => $identity->{uid},
radType => '', scriptingon => 'yup' } );
croak "Error during login process. " .
"The website is temporarily unavailable, stopped" if
$page =~ m|Service Temporarily Unvailable|i;
croak "Error during login process, stopped" if
lib/Finance/Bank/Natwest/Connection.pm view on Meta::CPAN
|ix;
croak "Error during login process. " .
"Unrecognised password request ($1, $2, $3), stopped" unless
exists POSS_PASS->{$1} &&
exists POSS_PASS->{$2} &&
exists POSS_PASS->{$3};
my $pass_chars = [ POSS_PASS->{$1}, POSS_PASS->{$2}, POSS_PASS->{$3} ];
my $pinpass = $self->{credentials}->get_pinpass( $pin_digits, $pass_chars );
$self->{credentials}->get_stop();
$page = $self->post('Logon-PinPass.asp',
{ pin1 => $pinpass->{pin}[0],
pin2 => $pinpass->{pin}[1],
pin3 => $pinpass->{pin}[2],
pass1 => $pinpass->{password}[0],
pass2 => $pinpass->{password}[1],
pass3 => $pinpass->{password}[2],
buttonComplete => 'Submitted',
buttonFinish => 'Finish' } );
lib/Finance/Bank/Natwest/CredentialsProvider/Callback.pm view on Meta::CPAN
use vars qw( $VERSION );
$VERSION = '0.03';
=head1 NAME
Finance::Bank::Natwest::CredentialsProvider::Callback - Credentials provider that uses a callback to gather the required information
=head1 DESCRIPTION
CredentialsProvider module that uses a callback to retrieve the credentials.
=head1 SYNOPSIS
my $credentials = Finance::Bank::Natwest::CredentialsProvider::Callback->new(
callback => \&credentials_callback
);
=head1 METHODS
=over 4
=item B<new>
my $credentials = Finance::Bank::Natwest::CredentialsProvider::Callback->new(
callback => \&credentials_callback
);
# Or we can also provide an ID to pass into the callback routine
my $credentials = Finance::Bank::Natwest::CredentialsProvider::Callback->new(
callback => \&credentials_callback, id => 1
);
If C<id> is provided then it must be a simple scalar, and not a reference.
=cut
sub new{
my ($class, %opts) = @_;
my $self = bless {}, $class;
lib/Finance/Bank/Natwest/CredentialsProvider/Constant.pm view on Meta::CPAN
package Finance::Bank::Natwest::CredentialsProvider::Constant;
use Carp;
use vars qw( $VERSION );
$VERSION = '0.03';
=head1 NAME
Finance::Bank::Natwest::CredentialsProvider::Constant - Static credentials provider
=head1 DESCRIPTION
CredentialsProvider module for static credentials.
=head1 SYNOPSIS
my $credentials = Finance::Bank::Natwest::CredentialsProvider::Constant->new(
dob => '010179', uid => '0001', password => 'Password', pin => '4321'
);
=head1 METHODS
=over 4
=item B<new>
my $credentials = Finance::Bank::Natwest::CredentialsProvider::Constant->new(
dob => '010179', uid => '0001', password => 'Password', pin => '4321'
);
# Or we can combine the dob and uid together
my $credentials = Finance::Bank::Natwest::CredentialsProvider::Constant->new(
customer_no => '0101790001', password => 'Password', pin => '4321'
);
All the parameters are mandatory in both forms of the constructor.
=cut
sub new{
my ($class, %opts) = @_;
t/callback.t view on Meta::CPAN
callback => $callback_info->[1] );
for my $callback (@{$callback_info->[0]}) {
my $callback_id = $callback->[0];
my $callback_identity = $callback->[1];
my $callback_pinpass = $callback->[2];
if (!defined $callback_identity) {
dies_ok {
$provider->get_start( id => $callback_id );
} 'Invalid id or invalid credentials: expected to fail';
} else {
$provider->get_start( id => $callback_id );
is_deeply( $provider->get_identity(), $callback_identity,
'Got expected identity' );
is_deeply( $provider->get_pinpass(
[0..@{$callback_pinpass->{pin}}-1],
[0..@{$callback_pinpass->{password}}-1] ),
$callback_pinpass,
t/connection.t view on Meta::CPAN
use Carp;
use Test::More tests => 15;
use Test::Exception;
use Mock::NatwestWebServer;
my $nws = Mock::NatwestWebServer->new();
use_ok( 'Finance::Bank::Natwest::Connection' );
for ( {},
{ credentials => 'Constant' },
{ credentials => 'UnknownCP' },
{ credentials => 'UnknownCP', credentials_options => {} },
{ credentials => bless {}, 'YetAnotherUnknownCP' },
{ credentials => {} },
{ credentials_options => {} } ) {
dies_ok {
my $nwb = Finance::Bank::Natwest::Connection->new(%{$_});
} 'invalid credential parameters: expected to fail';
}
{
my $nwb;
ok(
$nwb = Finance::Bank::Natwest::Connection->new(
credentials => 'Constant',
credentials_options => { customer_no => '0101790001',
password => 'Password',
pin => '1234' }
),
'valid credentials - getting ::Connection to create credentials object'
);
isa_ok( $nwb, 'Finance::Bank::Natwest::Connection' );
foreach my $method (qw( login post )) {
can_ok( $nwb, $method );
}
is( $nws->next_call(), undef, 'nothing but new() called yet' );
$nws->clear();
}
{
my $creds = Finance::Bank::Natwest::CredentialsProvider::Constant->new(
customer_no => '0101790001', password => 'Password', pin => '1234'
);
ok(
my $nwb = Finance::Bank::Natwest::Connection->new(
credentials => $creds ),
'valid credentials - providing premade credentials object'
);
$nws->add_account( dob => '010179', uid => '0001',
pin => '1234', pass => 'Password' );
$nwb->login();
ok( $nwb->{login_ok}, 'Logged in successfully' );
}
t/constant.t view on Meta::CPAN
%{$valid_details[0]}
);
isa_ok( $provider, 'Finance::Bank::Natwest::CredentialsProvider::Constant' );
foreach my $method (qw( get_start get_stop get_identity get_pinpass )) {
can_ok( $provider, $method );
}
}
foreach my $credentials (@invalid_details) {
dies_ok {
my $provider =
Finance::Bank::Natwest::CredentialsProvider::Constant->new(
%{$credentials} );
} 'invalid credentials: expected to fail';
}
foreach my $credentials (@valid_details) {
my $provider = Finance::Bank::Natwest::CredentialsProvider::Constant->new(
%{$credentials}
);
$provider->get_start();
is_deeply( $provider->get_identity(),
{ uid => '0001', dob => '010179' },
'Got expected identity' );
is_deeply( $provider->get_pinpass( [0,1,2,3], [0,1,2,3,4,5,6,7] ),
{ pin => ['4','3','2','1'],
t/fbn_creation.t view on Meta::CPAN
dies_ok {
my $fbn = Finance::Bank::Natwest->new();
} 'invalid credential parameters: expected to fail';
my $cred_obj = Finance::Bank::Natwest::CredentialsProvider::Constant->new(
customer_no => '0101790001', password => 'Password', pin => '4321'
);
dies_ok {
my $fbn = Finance::Bank::Natwest->new(
credentials => $cred_obj,
credentials_options => undef
);
} 'invalid credential parameters: expected to fail';
dies_ok {
my $fbn = Finance::Bank::Natwest->new(
credentials => $cred_obj,
credentials_options => {}
);
} 'invalid credential parameters: expected to fail';
dies_ok {
my $fbn = Finance::Bank::Natwest->new(
credentials => $cred_obj,
credentials_options => { customer_no => '0101790001',
password => 'Password',
pin => '4321'}
);
} 'invalid credential parameters: expected to fail';
dies_ok {
my $fbn = Finance::Bank::Natwest->new( credentials => 'Constant' );
} 'invalid credential parameters: expected to fail';
dies_ok {
my $fbn = Finance::Bank::Natwest->new( credentials => 'Callback' );
} 'invalid credential parameters: expected to fail';
dies_ok {
my $fbn = Finance::Bank::Natwest->new( credentials => 'GPG' );
} 'invalid credential parameters: expected to fail';
dies_ok {
my $fbn = Finance::Bank::Natwest->new(
credentials => 'Constant',
credentials_options => {}
);
} 'invalid credential parameters: expected to fail';
dies_ok {
my $fbn = Finance::Bank::Natwest->new(
credentials => 'Callback',
credentials_options => {}
);
} 'invalid credential parameters: expected to fail';
dies_ok {
my $fbn = Finance::Bank::Natwest->new( credentials_options => {} );
} 'invalid credentials parameters: expected to fail';
{
my $fbn = Finance::Bank::Natwest->new( credentials => 'Constant',
credentials_options => {
customer_no => '0101790001',
password => 'Password',
pin => '4321'
} );
isa_ok( $fbn, 'Finance::Bank::Natwest' );
foreach my $method (qw( accounts )) {
can_ok( $fbn, $method );
}
t/fbr_creation.t view on Meta::CPAN
dies_ok {
my $fbn = Finance::Bank::RBoS->new();
} 'invalid credential parameters: expected to fail';
my $cred_obj = Finance::Bank::Natwest::CredentialsProvider::Constant->new(
customer_no => '0101790001', password => 'Password', pin => '4321'
);
dies_ok {
my $fbn = Finance::Bank::RBoS->new(
credentials => $cred_obj,
credentials_options => undef
);
} 'invalid credential parameters: expected to fail';
dies_ok {
my $fbn = Finance::Bank::RBoS->new(
credentials => $cred_obj,
credentials_options => {}
);
} 'invalid credential parameters: expected to fail';
dies_ok {
my $fbn = Finance::Bank::RBoS->new(
credentials => $cred_obj,
credentials_options => { customer_no => '0101790001',
password => 'Password',
pin => '4321'}
);
} 'invalid credential parameters: expected to fail';
dies_ok {
my $fbn = Finance::Bank::RBoS->new( credentials => 'Constant' );
} 'invalid credential parameters: expected to fail';
dies_ok {
my $fbn = Finance::Bank::RBoS->new( credentials => 'Callback' );
} 'invalid credential parameters: expected to fail';
dies_ok {
my $fbn = Finance::Bank::RBoS->new( credentials => 'GPG' );
} 'invalid credential parameters: expected to fail';
dies_ok {
my $fbn = Finance::Bank::RBoS->new(
credentials => 'Constant',
credentials_options => {}
);
} 'invalid credential parameters: expected to fail';
dies_ok {
my $fbn = Finance::Bank::RBoS->new(
credentials => 'Callback',
credentials_options => {}
);
} 'invalid credential parameters: expected to fail';
dies_ok {
my $fbn = Finance::Bank::RBoS->new( credentials_options => {} );
} 'invalid credentials parameters: expected to fail';
{
my $fbn = Finance::Bank::RBoS->new( credentials => 'Constant',
credentials_options => {
customer_no => '0101790001',
password => 'Password',
pin => '4321'
} );
isa_ok( $fbn, 'Finance::Bank::RBoS' );
foreach my $method (qw( accounts )) {
can_ok( $fbn, $method );
}