fix double encoding on JSON UTF-8 custom fields

This commit is contained in:
Oliver Gorwits
2023-07-25 12:42:20 +01:00
parent 0b82499c77
commit e2ce601782
2 changed files with 14 additions and 5 deletions

View File

@@ -8,6 +8,7 @@ use App::Netdisco::Util::Device
use App::Netdisco::Backend::Job; use App::Netdisco::Backend::Job;
use Module::Load (); use Module::Load ();
use JSON::PP ();
use Try::Tiny; use Try::Tiny;
use base 'Exporter'; use base 'Exporter';
@@ -356,8 +357,9 @@ sub jq_insert {
die 'failed to find row for custom field update' unless $row; die 'failed to find row for custom field update' unless $row;
my $coder = JSON::PP->new->utf8(0)->allow_nonref(1)->allow_unknown(1);
$spec->{subaction} = $coder->encode( $spec->{extra} || $spec->{subaction} );
$spec->{action} =~ s/^cf_//; $spec->{action} =~ s/^cf_//;
$spec->{subaction} = to_json( $spec->{extra} || $spec->{subaction} );
$row->make_column_dirty('custom_fields'); $row->make_column_dirty('custom_fields');
$row->update({ $row->update({
custom_fields => \['jsonb_set(custom_fields, ?, ?)' custom_fields => \['jsonb_set(custom_fields, ?, ?)'

View File

@@ -16,6 +16,7 @@ use Dancer::Plugin::DBIC 'schema';
use Scope::Guard 'guard'; use Scope::Guard 'guard';
use NetAddr::IP::Lite ':lower'; use NetAddr::IP::Lite ':lower';
use Storable 'dclone'; use Storable 'dclone';
use JSON::PP ();
use Encode; use Encode;
register_worker({ phase => 'early', driver => 'snmp' }, sub { register_worker({ phase => 'early', driver => 'snmp' }, sub {
@@ -78,8 +79,10 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
# for existing device, filter custom_fields # for existing device, filter custom_fields
if ($device->in_storage) { if ($device->in_storage) {
my $coder = JSON::PP->new->utf8(0)->allow_nonref(1)->allow_unknown(1);
# get the custom_fields # get the custom_fields
my $fields = from_json ($device->custom_fields || '{}'); my $fields = $coder->decode(Encode::encode('UTF-8',$device->custom_fields) || '{}');
my %ok_fields = map {$_ => 1} my %ok_fields = map {$_ => 1}
grep {defined} grep {defined}
map {$_->{name}} map {$_->{name}}
@@ -88,10 +91,11 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
# filter custom_fields for current valid fields # filter custom_fields for current valid fields
foreach my $field (keys %$fields) { foreach my $field (keys %$fields) {
delete $fields->{$field} unless exists $ok_fields{$field}; delete $fields->{$field} unless exists $ok_fields{$field};
$fields->{$field} = Encode::decode('UTF-8', $fields->{$field});
} }
# set new custom_fields # set new custom_fields
$device->set_column( custom_fields => to_json $fields ); $device->set_column( custom_fields => $coder->encode($fields) );
} }
# support for Hooks # support for Hooks
@@ -383,8 +387,10 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
vars->{'hook_data'}->{'ports'} = [values %deviceports]; vars->{'hook_data'}->{'ports'} = [values %deviceports];
schema('netdisco')->resultset('DevicePort')->txn_do_locked(sub { schema('netdisco')->resultset('DevicePort')->txn_do_locked(sub {
my $coder = JSON::PP->new->utf8(0)->allow_nonref(1)->allow_unknown(1);
# backup the custom_fields # backup the custom_fields
my %fields = map {($_->{port} => from_json ($_->{custom_fields} || '{}'))} my %fields = map {($_->{port} => $coder->decode(Encode::encode('UTF-8',$_->{custom_fields} || '{}')))}
grep {exists $deviceports{$_->{port}}} grep {exists $deviceports{$_->{port}}}
$device->ports $device->ports
->search(undef, {columns => [qw/port custom_fields/]}) ->search(undef, {columns => [qw/port custom_fields/]})
@@ -399,10 +405,11 @@ register_worker({ phase => 'early', driver => 'snmp' }, sub {
foreach my $port (keys %fields) { foreach my $port (keys %fields) {
foreach my $field (keys %{ $fields{$port} }) { foreach my $field (keys %{ $fields{$port} }) {
delete $fields{$port}->{$field} unless exists $ok_fields{$field}; delete $fields{$port}->{$field} unless exists $ok_fields{$field};
$fields{$port}->{$field} = Encode::decode('UTF-8', $fields{$port}->{$field});
} }
# set new custom_fields # set new custom_fields
$deviceports{$port}->{custom_fields} = to_json $fields{$port}; $deviceports{$port}->{custom_fields} = $coder->encode($fields{$port});
} }
my $gone = $device->ports->delete({keep_nodes => 1}); my $gone = $device->ports->delete({keep_nodes => 1});