TT#56340 panel logline obfuscation

adds gdpr obfuscation quoting for:

+ subscriber numbers
+ subscriber ip addresses
+ subscriber usernames
+ any logmessage "DATA": query parameters, form data, response data
+ subscriber uuid's
+ call id's
+ callforward sip uri's

the quoting is centralized by $c->qs() ("quote sensitive"), using
catalyst plugin mechanism.

escape symbols are set to « (\x{ab}) and » (\x{bb}).

generate_logfile_data_inventory.pl was modified to mark loglines
with "gdpr affected" status, if $c->qs() was used in a log message.

Change-Id: I0f42d7992594232ae33e5666b0a64009211c5b76
changes/64/30464/14
Rene Krenn 7 years ago
parent 41e53f6d44
commit cae5270af5

@ -0,0 +1,13 @@
package Catalyst::Plugin::EscapeSensitiveValue;
use warnings;
use strict;
use MRO::Compat;
sub qs {
my $c = shift;
my $str = shift;
return "\x{ab}" . $str . "\x{bb}" if $str;
#return "<<" . $str . ">>" if $str;
}
1;

@ -26,6 +26,7 @@ use Catalyst qw/
Session
Session::Store::Redis
Session::State::Cookie
EscapeSensitiveValue
I18N
/;
use Log::Log4perl::Catalyst qw();

@ -191,7 +191,7 @@ sub POST :Allow {
});
die "Failed to populate capture agents\n" unless($res);
} catch($e) {
$c->log->error("failed to create interception: $e"); # TODO: user, message, trace, ...
$c->log->error("failed to create interception: " . $c->qs($e)); # TODO: user, message, trace, ...
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to create interception");
last;
}

@ -191,7 +191,7 @@ sub update_item_model {
);
} catch($e) {
$c->log->error("failed to update number: $e");
$c->log->error("failed to update number: " . $c->qs($e));
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to update number.");
return;
}

@ -51,7 +51,7 @@ sub POST :Allow {
my $guard = $c->model('DB')->txn_scope_guard;
{
my $resource = $self->get_valid_post_data(
c => $c,
c => $c,
media_type => 'application/json',
);
last unless $resource;
@ -102,13 +102,13 @@ sub POST :Allow {
last;
}
unless($sms) {
$c->log->error("failed to find sms with id $callid and token $token");
$c->log->error("failed to find sms with id " . $c->qs($callid) . " and token $token");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY,
"Failed to find sms with callid $callid and given token");
"Failed to find sms with callid " . $c->qs($callid) . " and given token");
last;
}
if($status eq "ACCEPT") {
$c->log->info("status for pcc sms of $callid is $status, forward sms");
$c->log->info("status for pcc sms of " . $c->qs($callid) . " is $status, forward sms");
my $smsc_peer = '';
my $smsc_peer_rs = NGCP::Panel::Utils::Preferences::get_dom_preference_rs(
c => $c, attribute => 'smsc_peer',
@ -135,7 +135,7 @@ sub POST :Allow {
last;
}
} else {
$c->log->info("status for pcc sms of $callid is $status, don't forward sms");
$c->log->info("status for pcc sms of " . $c->qs($callid) . " is $status, don't forward sms");
try {
$sms->update({ pcc_status => "complete" });
} catch($e) {

@ -408,8 +408,8 @@ sub POST :Allow {
);
} catch(DBIx::Class::Exception $e where { /Duplicate entry '([^']+)' for key 'number_idx'/ }) {
$e =~ /Duplicate entry '([^']+)' for key 'number_idx'/;
$c->log->error("failed to create subscriber, number $1 already exists"); # TODO: user, message, trace, ...
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Number '$1' already exists.");
$c->log->error("failed to create subscriber, number " . $c->qs($1) . " already exists"); # TODO: user, message, trace, ...
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Number '" . $c->qs($1) . "' already exists.");
last;
} catch($e) {
if (ref $error_info->{extended} eq 'HASH' && $error_info->{extended}->{response_code}) {

@ -90,7 +90,7 @@ sub GET :Allow {
$hal->resource({
total_count => $total_count,
});
my $response = HTTP::Response->new(HTTP_OK, undef,
my $response = HTTP::Response->new(HTTP_OK, undef,
HTTP::Headers->new($hal->http_headers(skip_links => 1)), $hal->as_json);
$c->response->headers($response->headers);
$c->response->body($response->content);
@ -105,7 +105,7 @@ sub POST :Allow {
my $guard = $c->model('DB')->txn_scope_guard;
{
my $resource = $self->get_valid_post_data(
c => $c,
c => $c,
media_type => 'application/json',
);
last unless $resource;
@ -140,7 +140,7 @@ sub POST :Allow {
try {
$item = $c->model('DB')->resultset('voip_trusted_sources')->create($resource);
} catch($e) {
$c->log->error("failed to create trusted source: $e"); # TODO: user, message, trace, ...
$c->log->error("failed to create trusted source: " . $c->qs($e)); # TODO: user, message, trace, ...
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to create trusted source.");
last;
}
@ -150,7 +150,7 @@ sub POST :Allow {
my ($c) = @_;
my $_item = $self->item_by_id($c, $item->id);
return $self->hal_from_item($c, $_item, $form); });
$guard->commit;
try {

@ -133,7 +133,7 @@ sub get_callmap :Chained('callflow_base') :PathPart('callmap') :Args(0) {
my $calls = [ $calls_rs->all ];
unless(@{ $calls }) {
$c->log->error("No packets for call-id $cid found");
$c->log->error("No packets for call-id " . $c->qs($cid) . " found");
$c->stash(messages => [{type => 'error', text => $c->loc('No packets for this Call-ID found.')}])
} else {
my $map = NGCP::Panel::Utils::Callflow::generate_callmap($c, $calls);

@ -294,7 +294,7 @@ sub base :Chained('list_customer') :PathPart('') :CaptureArgs(1) {
'me.id' => $c->user->account_id,
});
unless($contract_rs->count) {
$c->log->error("unauthorized access of subscriber uuid '".$c->user->uuid."' to contract id '$contract_id'");
$c->log->error("unauthorized access of subscriber uuid '".$c->qs($c->user->uuid)."' to contract id '$contract_id'");
$c->detach('/denied_page');
}
}

@ -1023,7 +1023,7 @@ sub get_annotated_info :Private {
iTotalRecords => 1,
iTotalDisplayRecords => 1,
iTotalRecordCountClipped => \0,
iTotalDisplayRecordCountClipped => \0,
iTotalDisplayRecordCountClipped => \0,
sEcho => int($c->request->params->{sEcho} // 1),
);
@ -1128,7 +1128,7 @@ sub dev_field_config :Chained('/') :PathPart('device/autoprov/config') :Args() {
($c->user_exists && ($c->user->roles eq "admin" || $c->user->roles eq "reseller")) ||
defined $c->request->env->{SSL_CLIENT_M_DN}
) {
$c->log->info("unauthenticated config access to id '$id' via ip " . $c->req->address);
$c->log->info("unauthenticated config access to id '$id' via ip " . $c->qs($c->req->address));
$c->response->content_type('text/plain');
if($c->config->{features}->{debug}) {
$c->response->body("403 - unauthenticated config access");
@ -1188,7 +1188,7 @@ sub dev_field_config :Chained('/') :PathPart('device/autoprov/config') :Args() {
$dn = lc($dn);
$dn =~ s/[:\-]//g;
if (index($dn, $id) == -1) {
$c->log->info("unauthorized config access to id '$id' from dn '$dn' via ip '$ip'");
$c->log->info("unauthorized config access to id '$id' from dn '" . $c->qs($dn) . "' via ip '" . $c->qs($ip) . "'");
$c->response->content_type('text/plain');
if($c->config->{features}->{debug}) {
$c->response->body("403 - unauthorized config access");
@ -1204,7 +1204,7 @@ sub dev_field_config :Chained('/') :PathPart('device/autoprov/config') :Args() {
identifier => $id
});
unless($dev) {
$c->log->warn("Unknown autoprov config '$id' for '$ip'");
$c->log->warn("Unknown autoprov config '$id' for '" . $c->qs($ip) . "'");
$c->response->content_type('text/plain');
if($c->config->{features}->{debug}) {
$c->response->body("404 - device id '" . $id . "' not found");
@ -1214,7 +1214,7 @@ sub dev_field_config :Chained('/') :PathPart('device/autoprov/config') :Args() {
$c->response->status(404);
return;
}
$c->log->info("Serving autoprov config for '$id' to '$ip'");
$c->log->info("Serving autoprov config for '$id' to '" . $c->qs($ip) . "'");
=pod
if(defined $yealink_key && defined $dev->encryption_key) {
@ -1513,7 +1513,7 @@ sub dev_field_bootstrap :Chained('/') :PathPart('device/autoprov/bootstrap') :Ar
identifier => $id
});
unless($dev) {
$c->log->warn("Unknown autoprov bootstrap config '$id' for '$ip'");
$c->log->warn("Unknown autoprov bootstrap config '$id' for '" . $c->qs($ip) . "'");
$c->response->content_type('text/plain');
if($c->config->{features}->{debug}) {
$c->response->body("404 - device id '" . $id . "' not found");
@ -1523,7 +1523,7 @@ sub dev_field_bootstrap :Chained('/') :PathPart('device/autoprov/bootstrap') :Ar
$c->response->status(404);
return;
}
$c->log->info("Serving autoprov bootstrap config for '$id' to '$ip'");
$c->log->info("Serving autoprov bootstrap config for '$id' to '" . $c->qs($ip) . "'");
my $model = $dev->profile->config->device;
@ -1739,7 +1739,7 @@ sub dev_static_jitsi_config :Chained('/') :PathPart('device/autoprov/static/jits
$server_port = $c->config->{sip}->{tls_port} // 5060;
$server_proto = $c->config->{sip}->{tls_port} ? 'TLS' : 'UDP';
$c->log->info("jitsiprov gathered required information, sipacc=$sipacc, xmppacc=$xmppacc");
$c->log->info("jitsiprov gathered required information, sipacc=" . $c->qs($sipacc) . ", xmppacc=" . $c->qs($xmppacc));
my $config = <<"EOF";
net.java.sip.communicator.plugin.provisioning.METHOD=Manual

@ -45,7 +45,7 @@ sub receive :Chained('list') :PathPart('receive') :Args(0) {
}
unless ($from && $to && $text && $token) {
$c->log->error("Missing one param of: from ($from), to ($to), text ($text), auth_token ($token).");
$c->log->error("Missing one param of: from (" . $c->qs($from) . "), to (" . $c->qs($to) . "), text ($text), auth_token ($token).");
$c->detach('/denied_page');
}
@ -69,7 +69,7 @@ sub receive :Chained('list') :PathPart('receive') :Args(0) {
})->first;
unless ($prov_dbalias) {
$c->log->warn("No corresponding subscriber for incoming number ($to) found.");
$c->log->warn("No corresponding subscriber for incoming number (" . $c->qs($to) . ") found.");
$c->log->debug("from: $from, to: $to, text: $text");
die "no_subscriber_found";
}
@ -129,7 +129,7 @@ sub receive :Chained('list') :PathPart('receive') :Args(0) {
type => 'cfs'
});
unless($cf_maps->count) {
$c->log->info("No cfs for inbound sms from $from to $to found.");
$c->log->info("No cfs for inbound sms from " . $c->qs($from) . " to " . $c->qs($to) . " found.");
last;
}
@ -140,18 +140,18 @@ sub receive :Chained('list') :PathPart('receive') :Args(0) {
if($map->source_set) {
$source_pass = 0;
foreach my $source($map->source_set->voip_cf_sources->all) {
$c->log->info(">>>> checking $from against ".$source->source);
$c->log->debug(">>>> checking $from against ".$source->source);
if(fnmatch($source->source, $from)) {
$c->log->info(">>>> matched $from against ".$source->source.", pass");
$c->log->debug(">>>> matched $from against ".$source->source.", pass");
$source_pass = 1;
last;
}
}
}
if($source_pass) {
$c->log->info(">>>> source check for $from passed, continue with time check");
$c->log->debug(">>>> source check for $from passed, continue with time check");
} else {
$c->log->info(">>>> source check for $from failed, trying next map entry");
$c->log->debug(">>>> source check for $from failed, trying next map entry");
next;
}
@ -167,38 +167,38 @@ sub receive :Chained('list') :PathPart('receive') :Args(0) {
$time->hour // '',
$time->minute // ''
);
$c->log->info(">>>> checking $now against ".$timestring);
$c->log->debug(">>>> checking $now against ".$timestring);
if(inPeriod($now, $timestring)) {
$c->log->info(">>>> matched $now against ".$timestring.", pass");
$c->log->debug(">>>> matched $now against ".$timestring.", pass");
$time_pass = 1;
last;
}
}
}
if($time_pass) {
$c->log->info(">>>> time check for $now passed, use destination set");
$c->log->debug(">>>> time check for $now passed, use destination set");
$dset = $map->destination_set;
last;
} else {
$c->log->info(">>>> time check for $now failed, trying next map entry");
$c->log->debug(">>>> time check for $now failed, trying next map entry");
next;
}
}
unless($dset) {
$c->log->info(">>>> checks failed, bailing out without forwarding");
$c->log->debug(">>>> checks failed, bailing out without forwarding");
last;
}
$c->log->info(">>>> proceed sms forwarding");
$c->log->debug(">>>> proceed sms forwarding");
unless($dset->voip_cf_destinations->first) {
$c->log->info(">>>> detected cf mapping has no destinations in destination set");
$c->log->debug(">>>> detected cf mapping has no destinations in destination set");
last;
}
my $dst = $dset->voip_cf_destinations->first->destination;
$dst =~ s/^sip:(.+)\@.+$/$1/;
$c->log->info(">>>> forward sms to $dst");
$c->log->debug(">>>> forward sms to $dst");
my $pcc_status = $pcc_enabled ? "pending" : "none";
my $fwd_item = NGCP::Panel::Utils::SMS::add_journal_record(

@ -74,7 +74,7 @@ sub customer_inv_list :Chained('/') :PathPart('invoice/customer') :CaptureArgs(1
if($c->user->roles eq "subscriberadmin" && $c->user->account_id != $contract_id) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => "access violation, subscriberadmin ".$c->user->uuid." with contract id ".$c->user->account_id." tries to access foreign contract id $contract_id",
error => "access violation, subscriberadmin ".$c->qs($c->user->uuid)." with contract id ".$c->user->account_id." tries to access foreign contract id $contract_id",
desc => $c->loc('Invalid contract id found'),
);
#NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/sound'));

@ -72,7 +72,7 @@ sub login_index :Path Form {
$c->response->redirect($target);
return;
} else {
$c->log->warn("invalid http login from '".$c->req->address."'");
$c->log->warn("invalid http login from '".$c->qs($c->req->address)."'");
$c->log->debug("*** Login::index auth failed");
$form->add_form_error($c->loc('Invalid username/password'));
}
@ -82,7 +82,7 @@ sub login_index :Path Form {
if ($form->has_errors) {
my $request_ip = $c->request->address;
$c->log->error("NGCP Panel Login failed realm=$realm ip=$request_ip");
$c->log->error("NGCP Panel Login failed realm=$realm ip=" . $c->qs($request_ip));
}
$c->stash(form => $form);

@ -127,7 +127,7 @@ sub auto :Private {
if($ssl_sn) {
$c->log->debug("++++++ Root::auto API request with client auth sn '$ssl_sn'");
unless($ssl_dn eq "/CN=Sipwise NGCP API client certificate") {
$c->log->error("++++++ Root::auto API request with invalid client DN '$ssl_dn'");
$c->log->error("++++++ Root::auto API request with invalid client DN '" . $c->qs($ssl_dn) . "'");
$c->res->status(403);
$c->res->body(JSON::to_json({
message => "Invalid client certificate DN '$ssl_dn'",
@ -141,7 +141,7 @@ sub auto :Private {
is_active => 1, # TODO: abused as password until NoPassword handler is available
}, 'api_admin_cert');
unless($c->user_exists) {
$c->log->warn("invalid api login from '".$c->req->address."'");
$c->log->warn("invalid api login from '".$c->qs($c->req->address)."'");
$c->detach(qw(API::Root invalid_user), [$ssl_sn]) unless $c->user_exists;
} else {
$c->log->debug("++++++ admin '".$c->user->login."' authenticated via api_admin_cert");
@ -152,7 +152,7 @@ sub auto :Private {
} elsif($c->user->read_only && !($c->req->method =~ /^(GET|HEAD|OPTIONS)$/)) {
$c->log->error("invalid method '".$c->req->method."' for read-only user '".$c->user->login."', rejecting");
$c->user->logout;
$c->log->error("++++ body data: " . $c->req->body_data);
$c->log->error("++++ body data: " . $c->qs($c->req->body_data));
$c->response->status(403);
$c->res->body(JSON::to_json({
message => "Invalid HTTP method for read-only user",
@ -170,7 +170,7 @@ sub auto :Private {
unless ($c->user_exists) {
$c->log->debug("+++++ invalid api admin system login");
$c->log->warn("invalid api system login from '".$c->req->address."'");
$c->log->warn("invalid api system login from '".$c->qs($c->req->address)."'");
}
$self->api_apply_fake_time($c);
@ -183,7 +183,7 @@ sub auto :Private {
unless ($c->user_exists) {
$c->log->debug("+++++ invalid api subscriber JWT login");
# $c->log->warn("invalid api system login from '".$c->req->address."'");
# $c->log->warn("invalid api system login from '".$c->qs($c->req->address)."'");
}
$self->api_apply_fake_time($c);
@ -204,7 +204,7 @@ sub auto :Private {
if ($c->user->domain->domain ne $d) {
$c->user->logout;
$c->log->debug("+++++ invalid api subscriber http login by '$username' (domain check failed)");
$c->log->warn("invalid api http login from '".$c->req->address."' by '$username'");
$c->log->warn("invalid api http login from '".$c->qs($c->req->address)."' by '" . $c->qs($username) ."'");
my $r = $c->get_auth_realm($realm);
$r->credential->authorization_required_response($c, $r);
return;
@ -213,7 +213,7 @@ sub auto :Private {
} else {
$c->user->logout if($c->user);
$c->log->debug("+++++ invalid api subscriber http login");
$c->log->warn("invalid api http login from '".$c->req->address."' by '$username'");
$c->log->warn("invalid api http login from '".$c->qs($c->req->address)."' by '" . $c->qs($username) ."'");
my $r = $c->get_auth_realm($realm);
$r->credential->authorization_required_response($c, $r);
return;
@ -359,7 +359,7 @@ sub end :Private {
my $incident = DateTime->from_epoch(epoch => Time::HiRes::time);
my $incident_id = sprintf '%X', $incident->strftime('%s%N');
my $incident_timestamp = DateTime::Format::RFC3339->new->format_datetime($incident);
$c->log->error("fatal error, id=$incident_id, timestamp=$incident_timestamp, error=".join(q(), @{ $c->error }));
$c->log->error("fatal error, id=$incident_id, timestamp=$incident_timestamp, error=".join(q(), map { $c->qs($_); } @{ $c->error }));
$c->clear_errors;
$c->stash(
exception_incident => $incident_id,

@ -86,7 +86,7 @@ sub contract_sets_list :Chained('/') :PathPart('sound/contract') :CaptureArgs(1)
if($c->user->roles eq "subscriberadmin" && $c->user->account_id != $contract_id) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => "access violation, subscriberadmin ".$c->user->uuid." with contract id ".$c->user->account_id." tries to access foreign contract id $contract_id",
error => "access violation, subscriberadmin ".$c->qs($c->user->uuid)." with contract id ".$c->user->account_id." tries to access foreign contract id $contract_id",
desc => $c->loc('Invalid contract id found'),
);
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/sound'));

@ -373,7 +373,7 @@ sub terminate :Chained('base') :PathPart('terminate') :Args(0) :Does(ACL) :ACLDe
if($c->user->roles eq 'subscriberadmin' && $c->user->uuid eq $subscriber->uuid) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => 'unauthorized termination of own subscriber for uuid '.$c->user->uuid,
error => 'unauthorized termination of own subscriber for uuid '.$c->qs($c->user->uuid),
desc => $c->loc('Terminating own subscriber is prohibited.'),
);
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/subscriber'));
@ -403,7 +403,7 @@ sub reset_webpassword :Chained('base') :PathPart('resetwebpassword') :Args(0) {
if($c->user->roles eq 'subscriberadmin' && $c->user->voip_subscriber->contract_id != $subscriber->contract_id) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => 'unauthorized password reset for subscriber uuid '.$c->user->uuid,
error => 'unauthorized password reset for subscriber uuid '.$c->qs($c->user->uuid),
desc => $c->loc('Invalid password reset attempt.'),
);
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/subscriber'));
@ -527,7 +527,7 @@ sub recover_webpassword :Chained('/') :PathPart('recoverwebpassword') :Args(0) {
unless($posted) {
unless($uuid_string && UUID::parse($uuid_string, $uuid_bin) != -1) {
$c->log->warn("invalid password recovery attempt for uuid '$uuid_string' from '".$c->req->address."'");
$c->log->warn("invalid password recovery attempt for uuid '$uuid_string' from '".$c->qs($c->req->address)."'");
$c->detach('/denied_page')
}
@ -538,7 +538,7 @@ sub recover_webpassword :Chained('/') :PathPart('recoverwebpassword') :Args(0) {
my $subscriber = $rs->first ? $rs->first->voip_subscriber : undef;
unless($subscriber) {
$c->log->warn("invalid password recovery attempt for uuid '$uuid_string' from '".$c->req->address."'");
$c->log->warn("invalid password recovery attempt for uuid '$uuid_string' from '".$c->qs($c->req->address)."'");
$c->detach('/denied_page');
}
}
@ -570,7 +570,7 @@ sub recover_webpassword :Chained('/') :PathPart('recoverwebpassword') :Args(0) {
$subscriber = $rs->first ? $rs->first->voip_subscriber : undef;
unless($subscriber && $subscriber->provisioning_voip_subscriber) {
$c->log->warn("invalid password recovery attempt for uuid '$uuid_string' from '".$c->req->address."'");
$c->log->warn("invalid password recovery attempt for uuid '$uuid_string' from '".$c->qs($c->req->address)."'");
$c->detach('/denied_page');
}
$subscriber->provisioning_voip_subscriber->update({
@ -3108,7 +3108,7 @@ sub aliases_ajax :Chained('master') :PathPart('ordergroups') :Args(0) :Does(ACL)
prefetch => ['subscriber', 'primary_number_owners_active'],
});
##other variant of the correct query is:
#my $num_rs = $c->model('DB')->resultset('voip_numbers')->search_rs({
# 'subscriber.contract_id' => $subscriber->contract_id,
@ -3119,10 +3119,10 @@ sub aliases_ajax :Chained('master') :PathPart('ordergroups') :Args(0) :Does(ACL)
#},{
# join => ['subscriber'],
#});
##produces query:
# SELECT `me`.`id`, `me`.`cc`, `me`.`ac`, `me`.`sn`, `me`.`reseller_id`, `me`.`subscriber_id`, `me`.`status`, `me`.`ported`, `me`.`list_timestamp`, ( concat(cc,' ',ac,' ',sn) ) AS `number`, `subscriber`.`username`
# FROM `billing`.`voip_numbers` `me`
# LEFT JOIN `billing`.`voip_subscribers` `subscriber` ON `subscriber`.`id` = `me`.`subscriber_id`
##produces query:
# SELECT `me`.`id`, `me`.`cc`, `me`.`ac`, `me`.`sn`, `me`.`reseller_id`, `me`.`subscriber_id`, `me`.`status`, `me`.`ported`, `me`.`list_timestamp`, ( concat(cc,' ',ac,' ',sn) ) AS `number`, `subscriber`.`username`
# FROM `billing`.`voip_numbers` `me`
# LEFT JOIN `billing`.`voip_subscribers` `subscriber` ON `subscriber`.`id` = `me`.`subscriber_id`
# WHERE ( ( ( `subscriber`.`id` != `subscriber`.`primary_number_id` OR `subscriber`.`status` = 'terminated' ) AND `subscriber`.`contract_id` = '789' ) ) ORDER BY `me`.`id`;
@ -3212,7 +3212,7 @@ sub edit_voicebox :Chained('base') :PathPart('preferences/voicebox/edit') :Args(
unless($vm_user) {
NGCP::Panel::Utils::Message::error(
c => $c,
log => "no voicemail user found for subscriber uuid ".$c->stash->{subscriber}->uuid,
log => "no voicemail user found for subscriber uuid ".$c->qs($c->stash->{subscriber}->uuid),
desc => $c->loc('Failed to find voicemail user.'),
);
NGCP::Panel::Utils::Navigation::back_or($c,
@ -3395,7 +3395,7 @@ sub edit_voicebox :Chained('base') :PathPart('preferences/voicebox/edit') :Args(
# default
NGCP::Panel::Utils::Message::error(
c => $c,
log => "trying to set invalid voicemail param '$attribute' for subscriber uuid ".$c->stash->{subscriber}->uuid,
log => "trying to set invalid voicemail param '$attribute' for subscriber uuid ".$c->qs($c->stash->{subscriber}->uuid),
desc => $c->loc('Invalid voicemail setting'),
);
NGCP::Panel::Utils::Navigation::back_or($c,
@ -3535,7 +3535,7 @@ sub edit_fax :Chained('base') :PathPart('preferences/fax/edit') :Args(1) {
# default
NGCP::Panel::Utils::Message::error(
c => $c,
log => "trying to set invalid fax param '$attribute' for subscriber uuid ".$c->stash->{subscriber}->uuid,
log => "trying to set invalid fax param '$attribute' for subscriber uuid ".$c->qs($c->stash->{subscriber}->uuid),
desc => $c->loc('Invalid fax setting.'),
);
NGCP::Panel::Utils::Navigation::back_or($c,
@ -3692,7 +3692,7 @@ sub edit_mail_to_fax :Chained('base') :PathPart('preferences/mail_to_fax/edit')
# default
NGCP::Panel::Utils::Message::error(
c => $c,
log => "trying to set invalid fax param '$attribute' for subscriber uuid ".$c->stash->{subscriber}->uuid,
log => "trying to set invalid fax param '$attribute' for subscriber uuid ".$c->qs($c->stash->{subscriber}->uuid),
desc => $c->loc('Invalid mailtofax setting.'),
);
NGCP::Panel::Utils::Navigation::back_or($c,
@ -4031,7 +4031,7 @@ sub voicemail :Chained('master') :PathPart('voicemail') :CaptureArgs(1) {
unless($rs->first) {
NGCP::Panel::Utils::Message::error(
c => $c,
log => "no such voicemail file with id '$vm_id' for uuid ".$c->stash->{subscriber}->uuid,
log => "no such voicemail file with id '$vm_id' for uuid ".$c->qs($c->stash->{subscriber}->uuid),
desc => $c->loc('No such voicemail file.'),
);
NGCP::Panel::Utils::Navigation::back_or($c,
@ -4105,7 +4105,7 @@ sub recording :Chained('master') :PathPart('recording') :CaptureArgs(1) {
unless($rs->first) {
NGCP::Panel::Utils::Message::error(
c => $c,
log => "no such recording with id '$rec_id' for uuid ".$c->stash->{subscriber}->uuid,
log => "no such recording with id '$rec_id' for uuid ".$c->qs($c->stash->{subscriber}->uuid),
desc => $c->loc('No such recording'),
);
NGCP::Panel::Utils::Navigation::back_or($c,
@ -4175,10 +4175,10 @@ sub delete_recording :Chained('recording') :PathPart('delete') :Args(0) {
my $recording = $c->stash->{recording};
my $data = { $recording->get_inflated_columns };
$c->model('DB')->schema->txn_do( sub {
NGCP::Panel::Utils::Subscriber::delete_callrecording(
c => $c,
recording => $recording,
force_delete => $form->values->{force_delete}
NGCP::Panel::Utils::Subscriber::delete_callrecording(
c => $c,
recording => $recording,
force_delete => $form->values->{force_delete}
);
});
NGCP::Panel::Utils::Message::info(
@ -4218,7 +4218,7 @@ sub registered :Chained('master') :PathPart('registered') :CaptureArgs(1) {
unless($c->stash->{registered}) {
NGCP::Panel::Utils::Message::error(
c => $c,
log => "failed to find location id '$reg_id' for subscriber uuid " . $s->uuid,
log => "failed to find location id '$reg_id' for subscriber uuid " . $c->qs($s->uuid),
desc => $c->loc('Failed to find registered device.'),
);
NGCP::Panel::Utils::Navigation::back_or($c,
@ -4365,7 +4365,7 @@ sub trusted_base :Chained('base') :PathPart('preferences/trusted') :CaptureArgs(
unless($c->stash->{trusted}) {
NGCP::Panel::Utils::Message::error(
c => $c,
log => "trusted source id '$trusted_id' not found for subscriber uuid ".$c->stash->{subscriber}->uuid,
log => "trusted source id '$trusted_id' not found for subscriber uuid ".$c->qs($c->stash->{subscriber}->uuid),
desc => $c->loc('Trusted source entry not found'),
);
NGCP::Panel::Utils::Navigation::back_or($c,
@ -4522,7 +4522,7 @@ sub upn_rewrite_base :Chained('base') :PathPart('preferences/upnrewrite') :Captu
unless($c->stash->{upn_rws}) {
NGCP::Panel::Utils::Message::error(
c => $c,
log => "rewrite set id '$rws_id' not found for subscriber uuid ".$c->stash->{subscriber}->uuid,
log => "rewrite set id '$rws_id' not found for subscriber uuid ".$c->qs($c->stash->{subscriber}->uuid),
desc => $c->loc('Rewrite Set entry not found'),
);
NGCP::Panel::Utils::Navigation::back_or($c,
@ -4721,7 +4721,7 @@ sub speeddial :Chained('base') :PathPart('preferences/speeddial') :CaptureArgs(1
unless($sd) {
NGCP::Panel::Utils::Message::error(
c => $c,
log => "no such speed dial slot with id '$sd_id' for uuid ".$c->stash->{subscriber}->uuid,
log => "no such speed dial slot with id '$sd_id' for uuid ".$c->qs($c->stash->{subscriber}->uuid),
desc => $c->loc('No such speed dial id.'),
);
NGCP::Panel::Utils::Navigation::back_or($c,
@ -4962,7 +4962,7 @@ sub ccmappings :Chained('base') :PathPart('preferences/ccmappings') :CaptureArgs
unless($ccmapping) {
NGCP::Panel::Utils::Message::error(
c => $c,
log => "no such ccmapping with id '$aa_id' for uuid ".$c->stash->{subscriber}->uuid,
log => "no such ccmapping with id '$aa_id' for uuid ".$c->qs($c->stash->{subscriber}->uuid),
desc => $c->loc('No such auto ccmapping id.'),
);
NGCP::Panel::Utils::Navigation::back_or($c,

@ -81,7 +81,7 @@ sub valprint {
my($self, $field) = @_;
my $c = $field->form->ctx;
$c->log->info("validating " . $field->name . "=" . $field->value);
$c->log->debug("validating " . $field->name . "=" . $field->value);
}
1;

@ -6,7 +6,7 @@ use parent qw/NGCP::Panel::Role::Journal/;
use NGCP::Panel::Utils::Generic qw(:all);
use boolean qw(true);
use Safe::Isa qw($_isa);
use Safe::Isa qw($_isa $_can);
use Storable qw();
use JSON qw();
use JSON::Pointer;
@ -248,10 +248,10 @@ sub validate_form {
if($run) {
# check keys/vals
$form->process(
params => $resource,
posted => 1,
%{$form_params},
item => $item,
params => $resource,
posted => 1,
%{$form_params},
item => $item,
no_update => 1
);
unless($form->validated) {
@ -260,7 +260,8 @@ sub validate_form {
$in //= '';
sprintf 'field=\'%s\', input=\'%s\', errors=\'%s\'',
($_->parent->$_isa('HTML::FormHandler::Field') ? $_->parent->name . '_' : '') . $_->name,
$in,
$in, #for now, we dont change the error response text, even if causes sensitive data in the logs.
#(($_->$_can('todo') && $_->todo()) ? $c->qs($in) : $in),
join('', @{ $_->errors })
} $form->error_fields;
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Validation failed. $e");
@ -740,7 +741,7 @@ sub paginate_order_collection_rs {
});
}
}
if ($explicit_order_col_spec ||
if ($explicit_order_col_spec ||
( $item_rs->result_source->can('has_column') && $item_rs->result_source->has_column($order_by) )) {
my $col = $explicit_order_col_spec || $item_rs->current_source_alias . '.' . $order_by;
if (lc($direction) eq 'desc') {
@ -814,7 +815,7 @@ sub collection_nav_links {
#now situation is so that forarray collections, total_count is always known
#it may change in case when e.g. kamailio rpc start to return requested info using paging too and we will start to use it
#so - in array collections we don't define now collection_infinite_pager_stop, but get total_count from array size.
if ( (! defined $total_count
if ( (! defined $total_count
&& ! $c->stash->{collection_infinite_pager_stop} )
|| ( defined $total_count && ($total_count / $rows) > $page ) ) {
@ -898,7 +899,7 @@ sub compare_patch_value {
my ($self, $c, $op, $value_current, $value_requested) = @_;
$value_requested //= $op->{value};
my $value_to_compare;
if ( ref $value_current eq 'HASH'
if ( ref $value_current eq 'HASH'
&& ref $value_requested eq 'HASH'
) {
my @keys = keys %$value_requested;
@ -1666,7 +1667,7 @@ sub mime_type_from_allowed_default {
my ($self, $c, $config_allowed_types, $system_default) = @_;
my $mime_type_from_config;
if ($config_allowed_types) {
if (!ref $config_allowed_types
if (!ref $config_allowed_types
&& $config_allowed_types ne $system_default ) {
$mime_type_from_config = $config_allowed_types;
} elsif (ref $config_allowed_types eq 'ARRAY'

@ -196,20 +196,20 @@ sub check_destinations{
}
for my $d (@{ $resource->{destinations} }) {
if (exists $d->{timeout} && ! is_int($d->{timeout})) {
$c->log->error("Invalid timeout for the destination '".$d->{destination}."'");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid timeout for the destination '".$d->{destination}."'");
$c->log->error("Invalid timeout for the destination '".$c->qs($d->{destination})."'");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid timeout for the destination '".$c->qs($d->{destination})."'");
return;
}
if (exists $d->{priority} && ! is_int($d->{priority})) {
$c->log->error("Invalid priority for the destination '".$d->{destination}."'");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid priority for the destination '".$d->{destination}."'");
$c->log->error("Invalid priority for the destination '".$c->qs($d->{destination})."'");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid priority for the destination '".$c->qs($d->{destination})."'");
return;
}
if (defined $d->{announcement_id}) {
#todo: I think that user expects that put and get will be the same
if(('customhours' ne $d->{destination}) && ('sip:custom-hours@app.local' ne $d->{destination}) ){
$c->log->error("Invalid parameter 'announcement_id' for the destination '".$d->{destination}."'");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid parameter 'announcement_id' for the destination '".$d->{destination}."'");
$c->log->error("Invalid parameter 'announcement_id' for the destination '".$c->qs($d->{destination})."'");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid parameter 'announcement_id' for the destination '".$c->qs($d->{destination})."'");
return;
}elsif(! is_int($d->{announcement_id})){
$c->log->error("Invalid announcement_id");

@ -150,8 +150,8 @@ sub update_item {
}
if (defined $d->{announcement_id}) {
if('customhours' ne $d->{destination}){
$c->log->error("Invalid parameter 'announcement_id' for the destination '".$d->{destination}."' in '$type'");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid parameter 'announcement_id' for the destination '".$d->{destination}."' in '$type'");
$c->log->error("Invalid parameter 'announcement_id' for the destination '".$c->qs($d->{destination})."' in '$type'");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid parameter 'announcement_id' for the destination '".$c->qs($d->{destination})."' in '$type'");
return;
}elsif(! is_int($d->{announcement_id})){
$c->log->error("Invalid announcement_id in '$type'");

@ -63,7 +63,7 @@ sub validate_request {
my $method = uc($c->request->method);
if ($method ne 'OPTIONS' && $method ne 'HEAD') {
my($owner,$type,$parameter,$value) = $self->check_owner_params($c);
return unless $owner;
return unless $owner;
}
return 1;
}
@ -158,7 +158,7 @@ sub check_owner_params {
unless ($owner) {
$c->log->error("Unknown $parameter value '$value'");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Unknown $parameter value '$value'");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Unknown $parameter value '$value'"); #$value is an id, so not sensitive.
return;
}
$c->stash->{check_owner_params} = [$owner,$type,$parameter,$value];

@ -31,7 +31,9 @@ sub hal_from_item {
config => $c->config,
include_id => $include_id,
err_code => sub {
$c->log->warn(shift); return;
my $rtc_error = shift;
$c->log->warn($rtc_error);
return;
});
} else {
}
@ -120,7 +122,9 @@ sub update_item {
config => $c->config,
reseller_item => $reseller,
err_code => sub {
$c->log->warn(shift); return;
my $rtc_error = shift;
$c->log->warn($rtc_error);
return;
});
try {

@ -243,7 +243,7 @@ sub _item_rs {
} elsif($c->user->roles eq "subscriber") {
$item_rs = $item_rs->search({
#voip_subscriber is a provisioning.voip_subscribers relation
#$c->user is provisioning.voip_subscribers, so we use ->voip_subscriber->id and compare to billing.voip-subscribers.
#$c->user is provisioning.voip_subscribers, so we use ->voip_subscriber->id and compare to billing.voip-subscribers.
'me.id' => $c->user->voip_subscriber->id,
});
} else {
@ -706,8 +706,8 @@ sub update_item {
);
} catch(DBIx::Class::Exception $e where { /Duplicate entry '([^']+)' for key 'number_idx'/ }) {
$e =~ /Duplicate entry '([^']+)' for key 'number_idx'/;
$c->log->error("failed to update subscriber, number $1 already exists"); # TODO: user, message, trace, ...
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Number '$1' already exists.");
$c->log->error("failed to update subscriber, number " . $c->qs($1) . " already exists"); # TODO: user, message, trace, ...
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Number '" . $c->qs($1) . "' already exists.");
return;
}
@ -801,7 +801,7 @@ sub subscriberadmin_write_access {
if ($c->user->roles eq "subscriberadmin"
&& (
( $c->config->{privileges}->{subscriberadmin}->{subscribers}
&& $c->config->{privileges}->{subscriberadmin}->{subscribers} =~/write/
&& $c->config->{privileges}->{subscriberadmin}->{subscribers} =~/write/
)
|| ( $c->config->{features}->{cloudpbx} #user can disable pbx feature after some time of using it
&& $c->user->contract->product->class eq 'pbxaccount'

@ -122,11 +122,11 @@ sub subresnum_from_number {
\[ 'concat(cc,ac,sn) = ?', [ {} => $number ]]
);
unless($num_rs->first) {
return 0 unless &{$err_code}("invalid number '$number'",'number',"Number does not exist");
return 0 unless &{$err_code}("invalid number '" . $c->qs($number) . "'",'number',"Number does not exist");
}
my $sub = $num_rs->first->subscriber;
unless($sub) {
return 0 unless &{$err_code}("invalid number '$number', not assigned to any subscriber",'number',"Number is not active");
return 0 unless &{$err_code}("invalid number '" . $c->qs($number) . "', not assigned to any subscriber",'number',"Number is not active");
}
my $res = $num_rs->first->reseller;
@ -135,7 +135,7 @@ sub subresnum_from_number {
# so take the long way here
$res = $sub->contract->contact->reseller;
unless($res) {
return 0 unless &{$err_code}("invalid number '$number', not assigned to any reseller",'number',"Number is not active");
return 0 unless &{$err_code}("invalid number '" . $c->qs($number) . "', not assigned to any reseller",'number',"Number is not active");
}
}

@ -43,17 +43,20 @@ sub get_log_params {
# remote user
my $r_user = '';
my $is_subscriber = 0;
if ($c->user_exists) {
if ($c->user->roles eq 'admin' || $c->user->roles eq 'reseller') {
$r_user = $c->user->login;
} elsif ($c->user->roles eq 'subscriberadmin' || $c->user->roles eq 'subscriber') {
$r_user = $c->user->webusername . '@' . $c->user->domain->domain;
$r_user = $c->qs($c->user->webusername . '@' . $c->user->domain->domain);
$is_subscriber = 1;
}
}
# remote ip
my $r_ip = $c->request->address;
$r_ip =~ s/^::ffff://; # ipv4 in ipv6 form -> ipv4
$r_user = $c->qs($r_ip) if $is_subscriber;
# parameters
my $data_str;
@ -88,9 +91,10 @@ sub get_log_params {
if (length($data_str) > 100000) {
# trim long messages
$data_str = "{ data => 'Msg size is too big' }";
} else {
$data_str = $c->qs($data_str);
}
return {
tx_id => $log_tx_id,
called => $called,
@ -178,7 +182,7 @@ sub error {
my $logstr = 'IP=%s CALLED=%s TX=%s USER=%s DATA=%s MSG="%s" LOG="%s"';
my $rc = $c->log->error(
sprintf $logstr, @{$log_params}{qw(r_ip called tx_id r_user data)}, $msg, $log_msg);
sprintf $logstr, @{$log_params}{qw(r_ip called tx_id r_user data)}, $c->qs($msg), $c->qs($log_msg));
if ($type eq 'panel') {
if (!defined $params{flash} || $params{flash} ) {
$c->flash(messages => [{ type => $usr_type,

@ -219,14 +219,11 @@ sub init_prepaid_billing {
my $use_list = { 'NGCP::Rating::Inew::SmsSession' => undef };
unless(can_load(modules => $use_list, nocache => 0, autoload => 0)) {
$c->log->error(sprintf
"Failed to load NGCP::Rating::Inew::SmsSession for sms=%s from=%s to=%s",
$session_id, $caller, $callee
);
$c->log->error(sprintf("Failed to load NGCP::Rating::Inew::SmsSession for sms=%s from=%s to=%s",$session_id, $c->qs($caller), $c->qs($callee)));
$session->{status} = 'failed';
$session->{reason} =
sprintf 'failed to init sms session sid=%s from=%s to=%s',
$session_id, $caller,$callee;
$session_id, $c->qs($caller), $c->qs($callee);
return;
}
my $amqr = NGCP::Rating::Inew::SmsSession::init(
@ -234,14 +231,11 @@ sub init_prepaid_billing {
$c->config->{libinewrate}->{openwire_uri},
);
unless($amqr) {
$c->log->error(sprintf
"Failed to create sms amqr handle for sms sid=%s from=%s to=%s",
$session_id, $caller, $callee
);
$c->log->error(sprintf("Failed to create sms amqr handle for sms sid=%s from=%s to=%s",$session_id, $c->qs($caller), $c->qs($callee)));
$session->{status} = 'failed';
$session->{reason} =
sprintf 'failed to create sms session sid=%s from=%s to=%s',
$session_id, $caller, $callee;
$session_id, $c->qs($caller), $c->qs($callee);
return;
}
$session->{amqr_h} = $amqr;
@ -261,19 +255,19 @@ sub init_prepaid_billing {
});
if (not defined $sess or $sess == -1) {
$c->log->error("Failed to create sms rating session from $caller to $callee with session id $this_session_id");
$c->log->error("Failed to create sms rating session from " . $c->qs($caller) . ' to ' . $c->qs($callee) . " with session id $this_session_id");
$session->{status} = 'failed';
$session->{reason} = 'failed to create sms session';
last;
} elsif ($sess == 0) {
$c->log->error("Remote denied sms rating session from $caller to $callee with session id $this_session_id (subscriber=inactive)");
$c->log->error("Remote denied sms rating session from " . $c->qs($caller) . ' to ' . $c->qs($callee) . " with session id $this_session_id (subscriber=inactive)");
$session->{status} = 'failed';
$session->{reason} = 'remote denied sms session (subscriber=inactive)';
last;
}
unless($has_credit) {
$c->log->info("No credit for sms from $caller to $callee with session id $this_session_id");
$c->log->info("No credit for sms from " . $c->qs($caller) . ' to ' . $c->qs($callee) . " with session id $this_session_id");
$session->{status} = 'failed';
$session->{reason} = 'insufficient credit';
NGCP::Rating::Inew::SmsSession::session_destroy($sess);
@ -283,7 +277,7 @@ sub init_prepaid_billing {
push @{$session->{parts}}, $sess;
unless(NGCP::Rating::Inew::SmsSession::session_sms_reserve($sess)) {
$c->log->error("Failed to reserve sms session from $caller to $callee with session id $this_session_id");
$c->log->error("Failed to reserve sms session from " . $c->qs($caller) . ' to ' . $c->qs($callee) . " with session id $this_session_id");
$session->{status} = 'failed';
$session->{reason} = 'failed to reserve sms session';
last;

@ -35,6 +35,7 @@ my $messages_count;
my $invocations_count;
my %distinct_variables;
my $extracted_message = undef;
my $is_sensitive = 0;
my $message_role = undef;
scancatalystlog();
@ -75,7 +76,7 @@ sub scancatalystlog_dir_names {
}
$message =~ s/\)(\s+(if|unless)[^;]+)?;(\s*#.+)?$//;
_dispatch_logfile(_list_variables({
gdpr_status => "#todo",
gdpr_status => ($message =~ /->qs\(/ ? 2 : 0),
level => $method,
log_line => $message,
source_file => $source_file_name,
@ -114,9 +115,10 @@ sub scanmessageslog_dir_names {
$line =~ s/^NGCP::Panel::Utils::Message::(info|error)\(/{/m;
$line =~ s/\)(\s+(if|unless)[^;]+)?;/}/m;
my $source_file_name = _get_source_file_name($inputfilename,$inputfiledir,$inputfilesuffix);
foreach my $message (_extract_messages($line,$method)) {
my %messages = _extract_messages($line,$method);
foreach my $message (keys %messages) {
_dispatch_logfile(_list_variables({
gdpr_status => "#todo",
gdpr_status => ($messages{$message} ? 2 : 0),
level => $method,
log_line => $message,
source_file => $source_file_name,
@ -213,11 +215,11 @@ sub _extract_messages {
if ($args and _run_message($method,$args,%vector)) {
if ($extracted_message
and index($extracted_message,'=HASH(0x') < 0) { # filter out nonsense vector stringifications
$dupe_results{$extracted_message} = 1;
$dupe_results{$extracted_message} = $dupe_results{$extracted_message} || $is_sensitive;
}
}
}
return keys %dupe_results;
return %dupe_results;
}
sub _run_message {
@ -228,6 +230,7 @@ sub _run_message {
role
/};
$extracted_message = undef;
$is_sensitive = 0;
$args->{flash} = 0;
$args->{stash} = 0;
$args->{c} = _create_mock('_c',
@ -266,6 +269,13 @@ sub _run_message {
my $self = shift;
return 1;
},
qs => sub {
my $self = shift;
my $str = shift;
$is_sensitive = 1;
#return "<<" . $str . ">>" if $str;
return "\x{ab}" . $str . "\x{bb}" if $str;
},
request => sub {
my $self = shift;
return _create_mock('_request',
@ -477,6 +487,13 @@ sub _deserialize_messagesargs {
}
return $str;
},
qs => sub {
my $self = shift;
my $str = shift;
$is_sensitive = 1;
#return "<<" . $str . ">>" if $str;
return "\x{ab}" . $str . "\x{bb}" if $str;
},
user => sub {
my $self = shift;
return _create_mock('user',
@ -601,7 +618,7 @@ sub _deserialize_messagesargs {
use Data::Dumper;
my $args = eval $_line;
if ($@) {
warn($@);
warn($_line ."\n" .$@);
return undef;
} else {
return $args;
@ -704,8 +721,10 @@ sub _dispatch_logfile {
push(@{$result{'panel-debug.log'}},$log_line);
} elsif (index($log_line->{log_line},'CALLED=API') >= 0) {
push(@{$result{'api.log'}},$log_line);
#print $log_line->{log_line} . "\n";
} else {
push(@{$result{'panel.log'}},$log_line);
#print $log_line->{log_line} . "\n";
}
}

Loading…
Cancel
Save