You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
474 lines
15 KiB
474 lines
15 KiB
package NGCP::Panel::Controller::SOAP::Intercept;
|
|
use NGCP::Panel::Utils::Generic qw(:all);
|
|
use Sipwise::Base;
|
|
|
|
use parent 'Catalyst::Controller';
|
|
|
|
use File::Slurp;
|
|
use SOAP::Transport::LOCAL;
|
|
|
|
sub thewsdl : GET Path('/SOAP/Intercept.wsdl') :Local :Args() {
|
|
my ($self, $c, $args) = @_;
|
|
|
|
my $thewsdl = read_file('/etc/ngcp-panel/Intercept.wsdl');
|
|
$c->response->body($thewsdl);
|
|
$c->response->content_type('text/xml');
|
|
}
|
|
|
|
sub intercept_index : POST Path('/SOAP/Intercept') {
|
|
my ($self, $c) = @_;
|
|
my $h = Sipwise::SOAP::Intercept->new(c => $c);
|
|
my $server = SOAP::Transport::LOCAL::Client->new;
|
|
$server->serializer->register_ns('http://dev.sipwise.com/SOAP/Provisioning/Types', 'typens');
|
|
my $out = $server
|
|
->dispatch_with({ 'urn:/SOAP/Intercept' => $h })
|
|
->handle($c->req->body);
|
|
$c->response->content_type('text/xml');
|
|
$c->response->body($out);
|
|
}
|
|
|
|
package Sipwise::SOAP::Intercept;
|
|
use Sipwise::Base;
|
|
use NGCP::Panel::Form;
|
|
use Data::Structure::Util qw/unbless/;
|
|
use NGCP::Panel::Utils::SOAP qw/typed/;
|
|
use NGCP::Panel::Utils::Interception qw();
|
|
use UUID;
|
|
use Moose;
|
|
use NGCP::Panel::Utils::Auth;
|
|
use Crypt::Eksblowfish::Bcrypt qw/bcrypt_hash en_base64 de_base64/;
|
|
|
|
has 'c' => (is => 'rw', isa => 'Object');
|
|
|
|
sub _validate {
|
|
my ($self, $form, $data) = @_;
|
|
|
|
unbless($data);
|
|
$form->process(params => $data);
|
|
unless($form->validated) {
|
|
if($form->has_form_errors) {
|
|
my @errs = $form->form_errors;
|
|
die SOAP::Fault
|
|
->faultcode('Client.Syntax.MissingParameter')
|
|
->faultstring(shift @errs);
|
|
} else {
|
|
my @fields = $form->error_fields;
|
|
my $field = shift @fields;
|
|
my @errs = $field->errors;
|
|
my $err = shift @errs;
|
|
die SOAP::Fault
|
|
->faultcode('Client.Syntax.MalformedParameter')
|
|
->faultstring($field->label . ": " . join('; ', @{ $err }));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
sub _auth {
|
|
my ($self, $auth) = @_;
|
|
my $c = $self->c;
|
|
|
|
$self->_validate(NGCP::Panel::Form::get("NGCP::Panel::Form::Intercept::Authentication", $c), $auth);
|
|
|
|
try {
|
|
|
|
# check for general availability of user first, we need it in
|
|
# both md5 and bcrypt cases
|
|
my $admin = $c->model('DB')->resultset('admins')->search({
|
|
login => $auth->{username},
|
|
is_active => 1,
|
|
})->first;
|
|
die unless($admin && ($admin->is_superuser || $admin->lawful_intercept));
|
|
|
|
if(defined $admin->saltedpass) {
|
|
my ($db_b64salt, $db_b64hash) = split /\$/, $admin->saltedpass;
|
|
my $salt = de_base64($db_b64salt);
|
|
my $usr_b64hash = en_base64(bcrypt_hash({
|
|
key_nul => 1,
|
|
cost => NGCP::Panel::Utils::Auth::get_bcrypt_cost(),
|
|
salt => $salt,
|
|
}, $auth->{password}));
|
|
|
|
die unless($usr_b64hash eq $db_b64hash);
|
|
die unless($admin->is_superuser || $admin->lawful_intercept);
|
|
} else {
|
|
my $md5admin = $c->model('DB')->resultset('admins')->search({
|
|
login => $auth->{username},
|
|
is_active => 1,
|
|
md5pass => { '=' => \['MD5("'.$auth->{password}.'")'] },
|
|
})->first;
|
|
die unless($md5admin && ($md5admin->is_superuser || $md5admin->lawful_intercept));
|
|
|
|
# migrate password to bcrypt
|
|
$admin->update({
|
|
md5pass => undef,
|
|
saltedpass => NGCP::Panel::Utils::Auth::generate_salted_hash($auth->{password}),
|
|
});
|
|
}
|
|
|
|
} catch($e) {
|
|
die SOAP::Fault
|
|
->faultcode('Client.Auth.Refused')
|
|
->faultstring("admin may not access LI data (wrong credentials or lawful_intercept flag not set)");
|
|
}
|
|
}
|
|
|
|
sub create_interception {
|
|
my ($self, $auth, $params) = @_;
|
|
my $c = $self->c;
|
|
|
|
$self->_auth($auth);
|
|
$self->_validate(NGCP::Panel::Form::get("NGCP::Panel::Form::Intercept::Create", $c), $params);
|
|
|
|
my ($sub, $reseller, $voip_number, $sip_username, $sip_domain);
|
|
try {
|
|
($sub, $reseller, $voip_number) = NGCP::Panel::Utils::Interception::subresnum_from_number($c, $params->{number}, sub {
|
|
my ($msg,$field,$response) = @_;
|
|
die SOAP::Fault
|
|
->faultcode('Client.Voip.NoSuchSubscriber')
|
|
->faultstring($msg);
|
|
return 0;
|
|
});
|
|
$sip_username = NGCP::Panel::Utils::Interception::username_to_regexp_pattern($c,$voip_number,$sub->username);
|
|
$sip_domain = $sub->domain->domain;
|
|
} catch($e) {
|
|
die $e if 'SOAP::Fault' eq ref $e;
|
|
die SOAP::Fault
|
|
->faultcode('Server.Internal')
|
|
->faultstring($e);
|
|
}
|
|
|
|
my ($uuid_bin, $uuid_string);
|
|
UUID::generate($uuid_bin);
|
|
UUID::unparse($uuid_bin, $uuid_string);
|
|
my $guard = $c->model('DB')->txn_scope_guard;
|
|
my $i;
|
|
{
|
|
try {
|
|
$i = $self->c->model('InterceptDB')->resultset('voip_intercept')->create({
|
|
reseller_id => $reseller->id,
|
|
LIID => $params->{LIID},
|
|
number => $params->{number},
|
|
cc_required => $params->{cc_required},
|
|
delivery_host => $params->{iri_delivery}->{host},
|
|
delivery_port => $params->{iri_delivery}->{port},
|
|
delivery_user => $params->{iri_delivery}->{user},
|
|
delivery_pass => $params->{iri_delivery}->{pass},
|
|
deleted => 0,
|
|
uuid => $uuid_string,
|
|
sip_username => $sip_username,
|
|
sip_domain => $sip_domain,
|
|
create_timestamp => \['NOW()'],
|
|
$params->{cc_required} ? (cc_delivery_host => $params->{cc_delivery}->{host}) : (),
|
|
$params->{cc_required} ? (cc_delivery_port => $params->{cc_delivery}->{port}) : (),
|
|
});
|
|
$guard->commit;
|
|
|
|
NGCP::Panel::Utils::Interception::request($c, 'POST', undef, {
|
|
liid => $i->LIID,
|
|
uuid => $i->uuid,
|
|
number => $i->number,
|
|
sip_username => $sip_username,
|
|
sip_domain => $sip_domain,
|
|
delivery_host => $i->delivery_host,
|
|
delivery_port => $i->delivery_port,
|
|
delivery_user => $i->delivery_user,
|
|
delivery_password => $i->delivery_pass,
|
|
cc_required => $i->cc_required,
|
|
cc_delivery_host => $i->cc_delivery_host,
|
|
cc_delivery_port => $i->cc_delivery_port,
|
|
});
|
|
} catch($e) {
|
|
die SOAP::Fault
|
|
->faultcode('Server.Internal')
|
|
->faultstring($e);
|
|
}
|
|
}
|
|
return typed($c, $i->id);
|
|
}
|
|
|
|
sub update_interception {
|
|
my ($self, $auth, $params) = @_;
|
|
my $c = $self->c;
|
|
|
|
$self->_auth($auth);
|
|
$self->_validate(NGCP::Panel::Form::get("NGCP::Panel::Form::Intercept::Update", $c), $params);
|
|
|
|
my $i;
|
|
try {
|
|
$i = $c->model('DB')->resultset('voip_intercept')->search({
|
|
id => $params->{id},
|
|
deleted => 0,
|
|
})->first;
|
|
} catch($e) {
|
|
die SOAP::Fault
|
|
->faultcode('Server.Internal')
|
|
->faultstring($e);
|
|
}
|
|
|
|
unless($i) {
|
|
die SOAP::Fault
|
|
->faultcode('Client.Intercept.NoSuchInterception')
|
|
->faultstring("interception ID '$$params{id}' does not exist");
|
|
}
|
|
|
|
my $guard = $c->model('DB')->txn_scope_guard;
|
|
{
|
|
if($params->{data}->{iri_delivery}) {
|
|
$i->delivery_host($params->{data}->{iri_delivery}->{host});
|
|
$i->delivery_port($params->{data}->{iri_delivery}->{port});
|
|
$i->delivery_user($params->{data}->{iri_delivery}->{username});
|
|
$i->delivery_pass($params->{data}->{iri_delivery}->{password});
|
|
}
|
|
if($params->{data}->{cc_delivery}) {
|
|
$i->cc_delivery_host($params->{data}->{cc_delivery}->{host});
|
|
$i->cc_delivery_port($params->{data}->{cc_delivery}->{port});
|
|
}
|
|
$i->cc_required($params->{data}->{cc_required});
|
|
# not applying changed number/domain?
|
|
|
|
try {
|
|
$i->update();
|
|
$guard->commit;
|
|
|
|
NGCP::Panel::Utils::Interception::request($c, 'PUT', $i->uuid, {
|
|
liid => $i->LIID,
|
|
uuid => $i->uuid,
|
|
number => $i->number,
|
|
sip_username => $i->sip_username,
|
|
sip_domain => $i->sip_domain,
|
|
delivery_host => $i->delivery_host,
|
|
delivery_port => $i->delivery_port,
|
|
delivery_user => $i->delivery_user,
|
|
delivery_password => $i->delivery_pass,
|
|
cc_required => $i->cc_required,
|
|
cc_delivery_host => $i->cc_delivery_host,
|
|
cc_delivery_port => $i->cc_delivery_port,
|
|
});
|
|
} catch($e) {
|
|
die SOAP::Fault
|
|
->faultcode('Server.Internal')
|
|
->faultstring($e);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
sub delete_interception {
|
|
my ($self, $auth, $params) = @_;
|
|
my $c = $self->c;
|
|
|
|
$self->_auth($auth);
|
|
$self->_validate(NGCP::Panel::Form::get("NGCP::Panel::Form::Intercept::Delete", $c), $params);
|
|
|
|
my $i;
|
|
try {
|
|
$i = $c->model('DB')->resultset('voip_intercept')->search({
|
|
id => $params->{id},
|
|
deleted => 0,
|
|
})->first;
|
|
} catch($e) {
|
|
die SOAP::Fault
|
|
->faultcode('Server.Internal')
|
|
->faultstring($e);
|
|
}
|
|
|
|
unless($i) {
|
|
die SOAP::Fault
|
|
->faultcode('Client.Intercept.NoSuchInterception')
|
|
->faultstring("interception ID '$$params{id}' does not exist");
|
|
}
|
|
|
|
my $guard = $c->model('DB')->txn_scope_guard;
|
|
{
|
|
try {
|
|
my $uuid = $i->uuid;
|
|
$i->update({
|
|
deleted => 1,
|
|
reseller_id => undef,
|
|
LIID => undef,
|
|
number => undef,
|
|
cc_required => 0,
|
|
delivery_host => undef,
|
|
delivery_port => undef,
|
|
delivery_user => undef,
|
|
delivery_pass => undef,
|
|
cc_delivery_host => undef,
|
|
cc_delivery_port => undef,
|
|
sip_username => undef,
|
|
sip_domain => undef,
|
|
uuid => undef,
|
|
});
|
|
$guard->commit;
|
|
|
|
NGCP::Panel::Utils::Interception::request($c, 'DELETE', $uuid);
|
|
} catch($e) {
|
|
die SOAP::Fault
|
|
->faultcode('Server.Internal')
|
|
->faultstring($e);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
sub get_interception_by_id {
|
|
my ($self, $auth, $params) = @_;
|
|
my $c = $self->c;
|
|
|
|
$self->_auth($auth);
|
|
|
|
my $i;
|
|
try {
|
|
$i = $c->model('DB')->resultset('voip_intercept')->search({
|
|
id => $params->{id},
|
|
deleted => 0,
|
|
})->first;
|
|
} catch($e) {
|
|
die SOAP::Fault
|
|
->faultcode('Server.Internal')
|
|
->faultstring($e);
|
|
}
|
|
|
|
unless($i) {
|
|
die SOAP::Fault
|
|
->faultcode('Client.Intercept.NoSuchInterception')
|
|
->faultstring("interception ID '$$params{id}' does not exist");
|
|
}
|
|
|
|
return typed($c, {
|
|
id => $i->id,
|
|
LIID => $i->LIID,
|
|
number => $i->number,
|
|
cc_required => $i->cc_required,
|
|
iri_delivery => {
|
|
host => $i->delivery_host,
|
|
port => $i->delivery_port,
|
|
username => $i->delivery_user,
|
|
password => $i->delivery_pass,
|
|
},
|
|
cc_delivery => {
|
|
host => $i->cc_delivery_host,
|
|
port => $i->cc_delivery_port,
|
|
}
|
|
});
|
|
}
|
|
|
|
sub get_interceptions_by_liid {
|
|
my ($self, $auth, $params) = @_;
|
|
my $c = $self->c;
|
|
|
|
$self->_auth($auth);
|
|
my @interceptions = ();
|
|
|
|
try {
|
|
my $rs = $c->model('DB')->resultset('voip_intercept')->search({
|
|
LIID => $params->{LIID},
|
|
deleted => 0,
|
|
});
|
|
while(my $i = $rs->next) {
|
|
push @interceptions, {
|
|
id => $i->id,
|
|
LIID => $i->LIID,
|
|
number => $i->number,
|
|
cc_required => $i->cc_required,
|
|
iri_delivery => {
|
|
host => $i->delivery_host,
|
|
port => $i->delivery_port,
|
|
username => $i->delivery_user,
|
|
password => $i->delivery_pass,
|
|
},
|
|
cc_delivery => {
|
|
host => $i->cc_delivery_host,
|
|
port => $i->cc_delivery_port,
|
|
}
|
|
};
|
|
}
|
|
} catch($e) {
|
|
die SOAP::Fault
|
|
->faultcode('Server.Internal')
|
|
->faultstring($e);
|
|
}
|
|
return typed($c, \@interceptions);
|
|
}
|
|
|
|
sub get_interceptions_by_number {
|
|
my ($self, $auth, $params) = @_;
|
|
my $c = $self->c;
|
|
|
|
$self->_auth($auth);
|
|
my @interceptions = ();
|
|
|
|
try {
|
|
my $rs = $c->model('DB')->resultset('voip_intercept')->search({
|
|
number => $params->{number},
|
|
deleted => 0,
|
|
});
|
|
while(my $i = $rs->next) {
|
|
push @interceptions, {
|
|
id => $i->id,
|
|
LIID => $i->LIID,
|
|
number => $i->number,
|
|
cc_required => $i->cc_required,
|
|
iri_delivery => {
|
|
host => $i->delivery_host,
|
|
port => $i->delivery_port,
|
|
username => $i->delivery_user,
|
|
password => $i->delivery_pass,
|
|
},
|
|
cc_delivery => {
|
|
host => $i->cc_delivery_host,
|
|
port => $i->cc_delivery_port,
|
|
}
|
|
};
|
|
}
|
|
} catch($e) {
|
|
die SOAP::Fault
|
|
->faultcode('Server.Internal')
|
|
->faultstring($e);
|
|
}
|
|
return typed($c, \@interceptions);
|
|
}
|
|
|
|
sub get_interceptions {
|
|
my ($self, $auth, $params) = @_;
|
|
my $c = $self->c;
|
|
|
|
$self->_auth($auth);
|
|
my @interceptions = ();
|
|
|
|
try {
|
|
my $rs = $c->model('DB')->resultset('voip_intercept')->search({
|
|
deleted => 0,
|
|
});
|
|
while(my $i = $rs->next) {
|
|
push @interceptions, {
|
|
id => $i->id,
|
|
LIID => $i->LIID,
|
|
number => $i->number,
|
|
cc_required => $i->cc_required,
|
|
iri_delivery => {
|
|
host => $i->delivery_host,
|
|
port => $i->delivery_port,
|
|
username => $i->delivery_user,
|
|
password => $i->delivery_pass,
|
|
},
|
|
cc_delivery => {
|
|
host => $i->cc_delivery_host,
|
|
port => $i->cc_delivery_port,
|
|
}
|
|
};
|
|
}
|
|
} catch($e) {
|
|
die SOAP::Fault
|
|
->faultcode('Server.Internal')
|
|
->faultstring($e);
|
|
}
|
|
return typed($c, \@interceptions);
|
|
}
|
|
|
|
|
|
|
|
1;
|
|
|
|
# vim: set tabstop=4 expandtab:
|