From 0670574996ed162725f0151547f82e03811d8e8f Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Fri, 14 Feb 2025 16:22:35 +0000 Subject: [PATCH] Bug 39190: Remove old objects Signed-off-by: Kyle M Hall --- Koha/SFTP/Server.pm | 446 --------------------------- Koha/SFTP/Servers.pm | 55 ---- admin/sftp_servers.pl | 1 - t/db_dependent/Koha/SFTP/Server.t | 167 ---------- t/db_dependent/api/v1/sftp_servers.t | 23 +- 5 files changed, 11 insertions(+), 681 deletions(-) delete mode 100644 Koha/SFTP/Server.pm delete mode 100644 Koha/SFTP/Servers.pm delete mode 100755 t/db_dependent/Koha/SFTP/Server.t diff --git a/Koha/SFTP/Server.pm b/Koha/SFTP/Server.pm deleted file mode 100644 index d91a20116cd..00000000000 --- a/Koha/SFTP/Server.pm +++ /dev/null @@ -1,446 +0,0 @@ -package Koha::SFTP::Server; - -# This file is part of Koha. -# -# Koha is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# Koha is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Koha; if not, see . - -use Modern::Perl; - -use Koha::Database; -use Koha::Exceptions::Object; -use Koha::Encryption; -use Koha::Logger; -use Koha::SFTP::Servers; - -use Try::Tiny qw( catch try ); -use Mojo::JSON; -use Net::SFTP::Foreign; -use Net::FTP; -use File::Spec; -use IO::File; - -use base qw(Koha::Object); - -=head1 NAME - -Koha::SFTP::Server - Koha SFTP Server Object class - -=head1 API - -=head2 Class methods - -=head3 store - - $server->store; - -Overloaded store method that ensures directory paths end with a forward slash. - -=cut - -sub store { - my ($self) = @_; - - for my $dir_field (qw( download_directory upload_directory )) { - my $dir = $self->$dir_field; - next unless $dir && $dir ne ''; - - $self->$dir_field( $dir . '/' ) unless substr( $dir, -1 ) eq '/'; - } - - return $self->SUPER::store; -} - -=head3 to_api - - my $json = $sftp_server->to_api; - -Returns a JSON representation of the object suitable for API output, -excluding sensitive data. - -=cut - -sub to_api { - my ( $self, $params ) = @_; - - my $json_sftp = $self->SUPER::to_api($params) or return; - delete $json_sftp->{password}; - delete $json_sftp->{key_file}; - - return $json_sftp; -} - -=head3 to_api_mapping - -This method returns the mapping for representing a Koha::SFTP::Server object -on the API. - -=cut - -sub to_api_mapping { - return { id => 'sftp_server_id' }; -} - -=head3 plain_text_password - - my $password = $server->plain_text_password; - -Returns the decrypted plaintext password. - -=cut - -sub plain_text_password { - my ($self) = @_; - return unless $self->password; - return Koha::Encryption->new->decrypt_hex( $self->password ); -} - -=head3 plain_text_key - - my $key = $server->plain_text_key; - -Returns the decrypted plaintext key file. - -=cut - -sub plain_text_key { - my ($self) = @_; - return unless $self->key_file; - return Koha::Encryption->new->decrypt_hex( $self->key_file ) . "\n"; -} - -=head3 write_key_file - - my $success = $server->write_key_file; - -Writes the keyfile from the db into a file. - -Returns 1 on success, undef on failure. - -=cut - -sub write_key_file { - my ($self) = @_; - - my $upload_path = C4::Context->config('upload_path') or return; - my $logger = Koha::Logger->get; - my $key_path = File::Spec->catdir( $upload_path, 'ssh_keys' ); - my $key_file = File::Spec->catfile( $key_path, 'id_ssh_' . $self->id ); - - mkdir $key_path unless -d $key_path; - unlink $key_file if -f $key_file; - - my $fh = IO::File->new( $key_file, 'w' ) or return; - - try { - chmod 0600, $key_file if -f $key_file; - print $fh $self->plain_text_key; - close $fh or $logger->warn("Failed to close key file: $!"); - return 1; - } catch { - $logger->warn("Error writing key file: $_"); - close $fh; - return; - }; -} - -=head3 locate_key_file - - my $path = $server->locate_key_file; - -Returns the keyfile's path if it exists, undef otherwise. - -=cut - -sub locate_key_file { - my ($self) = @_; - - my $upload_path = C4::Context->config('upload_path') or return; - my $key_file = File::Spec->catfile( - $upload_path, - 'ssh_keys', - 'id_ssh_' . $self->id - ); - - return ( -f $key_file ) ? $key_file : undef; -} - -=head3 update_password - - my $success = $server->update_password; - -Update the server's encrypted password. - -=cut - -sub update_password { - my ( $self, $value ) = @_; - return unless defined $value; - - $self->password( Koha::Encryption->new->encrypt_hex($value) ); - return $self->SUPER::store; -} - -=head3 update_key_file - - my $success = $server->update_key_file($new_key_file); - -Update the server's encrypted key file. - -=cut - -sub update_key_file { - my ( $self, $value ) = @_; - return unless defined $value; - - $self->key_file( Koha::Encryption->new->encrypt_hex( _dos2unix($value) ) ); - return $self->SUPER::store; -} - -=head3 update_status - - my $success = $server->update_status($new_status); - -Update the server's status - -=cut - -sub update_status { - my ( $self, $value ) = @_; - return unless defined $value; - - return $self->set( { status => $value } )->store; -} - -=head3 test_conn - - my ($success, $results) = $server->test_conn; - -Tests connection to the server. Returns success flag and detailed test results. - -=cut - -sub test_conn { - my ($self) = @_; - my $default_result = { - passed => Mojo::JSON->false, - err => undef, - msg => undef, - }; - my $sftp_test_results; - - if ( $self->transport eq 'sftp' ) { - $sftp_test_results->{'1_sftp_conn'} = {%$default_result}; - my $sftp = Net::SFTP::Foreign->new( - host => $self->host, - user => $self->user_name, - password => $self->plain_text_password, - key_path => $self->locate_key_file, - port => $self->port, - timeout => 10, - more => [ - qw(-vv), - qw(-o StrictHostKeyChecking=no), - ], - ); - unless ( $sftp->error ) { - $sftp_test_results->{'1_sftp_conn'}->{'passed'} = Mojo::JSON->true; - $sftp_test_results->{'1_sftp_conn'}->{'msg'} = $sftp->status; - } else { - $sftp_test_results->{'1_sftp_conn'}->{'err'} = $sftp->error; - } - - unless ( $sftp->error ) { - unless ( $self->download_directory eq '' ) { - $sftp_test_results->{'2a_sftp_cwd_dl'} = {%$default_result}; - $sftp->setcwd( $self->download_directory ); - unless ( $sftp->error ) { - $sftp_test_results->{'2a_sftp_cwd_dl'}->{'passed'} = Mojo::JSON->true; - $sftp_test_results->{'2a_sftp_cwd_dl'}->{'msg'} = $sftp->status; - } else { - $sftp_test_results->{'2a_sftp_cwd_dl'}->{'err'} = $sftp->error; - } - } - - $sftp_test_results->{'2b_sftp_ls_dl'} = {%$default_result}; - $sftp->ls(); - unless ( $sftp->error ) { - $sftp_test_results->{'2b_sftp_ls_dl'}->{'passed'} = Mojo::JSON->true; - $sftp_test_results->{'2b_sftp_ls_dl'}->{'msg'} = $sftp->status; - } else { - $sftp_test_results->{'2b_sftp_ls_dl'}->{'err'} = $sftp->error; - } - - unless ( $self->upload_directory eq '' ) { - $sftp_test_results->{'2c_sftp_cwd_ul'} = {%$default_result}; - $sftp->setcwd( $self->upload_directory ); - unless ( $sftp->error ) { - $sftp_test_results->{'2c_sftp_cwd_ul'}->{'passed'} = Mojo::JSON->true; - $sftp_test_results->{'2c_sftp_cwd_ul'}->{'msg'} = $sftp->status; - } else { - $sftp_test_results->{'2c_sftp_cwd_ul'}->{'err'} = $sftp->error; - } - } - - $sftp_test_results->{'2d_sftp_ls_ul'} = {%$default_result}; - $sftp->ls( $self->upload_directory ); - unless ( $sftp->error ) { - $sftp_test_results->{'2d_sftp_ls_ul'}->{'passed'} = Mojo::JSON->true; - $sftp_test_results->{'2d_sftp_ls_ul'}->{'msg'} = $sftp->status; - } else { - $sftp_test_results->{'2d_sftp_ls_ul'}->{'err'} = $sftp->error; - } - - $sftp_test_results->{'3_sftp_write'} = {%$default_result}; - open my $fh, '<', \"Hello, world!\n"; - close $fh if ( $sftp->put( $fh, $self->upload_directory . '.koha_test_file' ) ); - unless ( $sftp->error ) { - $sftp_test_results->{'3_sftp_write'}->{'passed'} = Mojo::JSON->true; - $sftp_test_results->{'3_sftp_write'}->{'msg'} = $sftp->status; - } else { - $sftp_test_results->{'3_sftp_write'}->{'err'} = $sftp->error; - } - - $sftp_test_results->{'4_sftp_del'} = {%$default_result}; - $sftp->remove( $self->upload_directory . '.koha_test_file' ); - unless ( $sftp->error ) { - $sftp_test_results->{'4_sftp_del'}->{'passed'} = Mojo::JSON->true; - $sftp_test_results->{'4_sftp_del'}->{'msg'} = $sftp->status; - } else { - $sftp_test_results->{'4_sftp_del'}->{'err'} = $sftp->error; - } - } - } elsif ( $self->transport eq 'ftp' ) { - $sftp_test_results->{'1_ftp_conn'} = {%$default_result}; - my $ftp = Net::FTP->new( - $self->host, - Port => $self->port, - Timeout => 10, - Passive => ( scalar $self->passive ) ? 1 : 0, - ); - if ($ftp) { - $sftp_test_results->{'1_ftp_conn'}->{'passed'} = Mojo::JSON->true; - $sftp_test_results->{'1_ftp_conn'}->{'msg'} = $ftp->message; - } else { - $sftp_test_results->{'1_ftp_conn'}->{'err'} = 'cannot connect to ' . $self->host . ': ' . $@; - } - - if ($ftp) { - $sftp_test_results->{'2_ftp_login'} = {%$default_result}; - my $login = $ftp->login( - $self->user_name, - $self->plain_text_password, - ); - if ($login) { - $sftp_test_results->{'2_ftp_login'}->{'passed'} = Mojo::JSON->true; - $sftp_test_results->{'2_ftp_login'}->{'msg'} = $ftp->message; - } else { - $sftp_test_results->{'2_ftp_login'}->{'err'} = $ftp->message; - } - - unless ( $self->download_directory eq '' ) { - $sftp_test_results->{'3a_ftp_cwd_dl'} = {%$default_result}; - my $cwd_dl = $ftp->cwd( $self->download_directory ); - if ($cwd_dl) { - $sftp_test_results->{'3a_ftp_cwd_dl'}->{'passed'} = Mojo::JSON->true; - $sftp_test_results->{'3a_ftp_cwd_dl'}->{'msg'} = $ftp->message; - } else { - $sftp_test_results->{'3a_ftp_cwd_dl'}->{'err'} = $ftp->message; - } - } - - $sftp_test_results->{'3b_ftp_ls_dl'} = {%$default_result}; - my $ls_dl = $ftp->ls(); - if ($ls_dl) { - $sftp_test_results->{'3b_ftp_ls_dl'}->{'passed'} = Mojo::JSON->true; - $sftp_test_results->{'3b_ftp_ls_dl'}->{'msg'} = $ftp->message; - } else { - $sftp_test_results->{'3b_ftp_ls_dl'}->{'err'} = $ftp->message; - } - - unless ( $self->upload_directory eq '' ) { - $sftp_test_results->{'3c_ftp_cwd_ul'} = {%$default_result}; - my $cwd_ul = $ftp->cwd( $self->upload_directory ); - if ($cwd_ul) { - $sftp_test_results->{'3c_ftp_cwd_ul'}->{'passed'} = Mojo::JSON->true; - $sftp_test_results->{'3c_ftp_cwd_ul'}->{'msg'} = $ftp->message; - } else { - $sftp_test_results->{'3c_ftp_cwd_ul'}->{'err'} = $ftp->message; - } - } - - $sftp_test_results->{'3d_ftp_ls_ul'} = {%$default_result}; - my $ls_ul = $ftp->ls(); - if ($ls_ul) { - $sftp_test_results->{'3d_ftp_ls_ul'}->{'passed'} = Mojo::JSON->true; - $sftp_test_results->{'3d_ftp_ls_ul'}->{'msg'} = $ftp->message; - } else { - $sftp_test_results->{'3d_ftp_ls_ul'}->{'err'} = $ftp->message; - } - - $sftp_test_results->{'4_ftp_write'} = {%$default_result}; - open my $fh, '<', \"Hello, world!\n"; - close $fh if ( my $put = $ftp->put( $fh, $self->upload_directory . '.koha_test_file' ) ); - if ($put) { - $sftp_test_results->{'4_ftp_write'}->{'passed'} = Mojo::JSON->true; - $sftp_test_results->{'4_ftp_write'}->{'msg'} = $ftp->message; - } else { - $sftp_test_results->{'4_ftp_write'}->{'err'} = $ftp->message; - } - - $sftp_test_results->{'5_ftp_del'} = {%$default_result}; - my $delete = $ftp->delete( $self->upload_directory . '.koha_test_file' ); - if ($delete) { - $sftp_test_results->{'5_ftp_del'}->{'passed'} = Mojo::JSON->true; - $sftp_test_results->{'5_ftp_del'}->{'msg'} = $ftp->message; - } else { - $sftp_test_results->{'5_ftp_del'}->{'err'} = $ftp->message; - } - } - } - - # $self->update_status('tests_ok'); - # foreach my $val ( values %$sftp_test_results ) { - # if ( defined $val->{'err'} ) { - # $self->update_status('tests_failed'); - # } - # } - - return ( 1, $sftp_test_results ); -} - -=head2 Internal methods - -=head3 _dos2unix - -Return a CR-free string from an input - -=cut - -sub _dos2unix { - my $dosStr = shift; - - return $dosStr =~ s/\015\012/\012/gr; -} - -=head3 _type - -Return type of Object relating to Schema ResultSet - -=cut - -sub _type { - return 'SftpServer'; -} - -1; diff --git a/Koha/SFTP/Servers.pm b/Koha/SFTP/Servers.pm deleted file mode 100644 index 6859bbe2e45..00000000000 --- a/Koha/SFTP/Servers.pm +++ /dev/null @@ -1,55 +0,0 @@ -package Koha::SFTP::Servers; - -# This file is part of Koha. -# -# Koha is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# Koha is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Koha; if not, see . - -use Modern::Perl; - -use Koha::Database; -use Koha::Exceptions; - -use Koha::SFTP::Server; - -use base qw(Koha::Objects); - -=head1 NAME - -Koha::SFTP::Servers - Koha SFTP Server Object set class - -=head1 API - -=head2 Internal methods - -=head3 _type - -Return type of object, relating to Schema ResultSet - -=cut - -sub _type { - return 'SftpServer'; -} - -=head3 object_class - -Return object class - -=cut - -sub object_class { - return 'Koha::SFTP::Server'; -} - -1; diff --git a/admin/sftp_servers.pl b/admin/sftp_servers.pl index 5c19edc30d7..1be83acea9a 100755 --- a/admin/sftp_servers.pl +++ b/admin/sftp_servers.pl @@ -26,7 +26,6 @@ use Try::Tiny qw( catch try ); use C4::Auth qw( get_template_and_user ); use C4::Output qw( output_html_with_http_headers ); -use Koha::SFTP::Servers; use Koha::File::Transports; my $input = CGI->new; diff --git a/t/db_dependent/Koha/SFTP/Server.t b/t/db_dependent/Koha/SFTP/Server.t deleted file mode 100755 index ee53f38e98d..00000000000 --- a/t/db_dependent/Koha/SFTP/Server.t +++ /dev/null @@ -1,167 +0,0 @@ -#!/usr/bin/perl - -# This file is part of Koha. -# -# Koha is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# Koha is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Koha; if not, see . - -use Modern::Perl; - -use Test::More tests => 7; -use Test::Exception; -use Test::Warn; - -use Koha::SFTP::Servers; - -use t::lib::TestBuilder; -use t::lib::Mocks; - -my $schema = Koha::Database->new->schema; -my $builder = t::lib::TestBuilder->new; - -subtest 'to_api() tests' => sub { - - plan tests => 2; - - $schema->storage->txn_begin; - - my $sftp_server = $builder->build_object( { class => 'Koha::SFTP::Servers' } ); - - ok( !exists $sftp_server->to_api->{password}, 'Password is not part of the API representation' ); - ok( !exists $sftp_server->to_api->{key_file}, 'Key file is not part of the API representation' ); - - $schema->storage->txn_rollback; -}; - -subtest 'update_password() tests' => sub { - - plan tests => 2; - - $schema->storage->txn_begin; - - my $sftp_server = $builder->build_object( { class => 'Koha::SFTP::Servers' } ); - $sftp_server->update_password('test123'); - - ok( $sftp_server->password ne 'test123', 'Password should not be in plain text' ); - is( length( $sftp_server->password ), 64, 'Password has should be 64 characters long' ); - - $schema->storage->txn_rollback; -}; - -subtest 'update_key_file() tests' => sub { - - plan tests => 2; - - $schema->storage->txn_begin; - - my $sftp_server = $builder->build_object( { class => 'Koha::SFTP::Servers' } ); - $sftp_server->update_key_file('321tset'); - - ok( $sftp_server->key_file ne 'test123', 'Password should not be in plain text' ); - is( length( $sftp_server->key_file ), 64, 'Password has should be 64 characters long' ); - - $schema->storage->txn_rollback; -}; - -subtest 'update_status() tests' => sub { - - plan tests => 2; - - $schema->storage->txn_begin; - - my $sftp_server = $builder->build_object( { class => 'Koha::SFTP::Servers' } ); - my $sftp_server_status = 'tests_ok'; - - $sftp_server->set( - { - password => 'somepass', - key_file => 'somekey', - } - )->store; - - isnt( $sftp_server_status, $sftp_server->status, 'Status should not by tests_ok' ); - - $sftp_server->update_status($sftp_server_status); - - is( $sftp_server_status, $sftp_server->status, 'Status should be tests_ok' ); - - $schema->storage->txn_rollback; - -}; - -subtest 'plain_text_password() tests' => sub { - - plan tests => 2; - - $schema->storage->txn_begin; - - my $sftp_server = $builder->build_object( { class => 'Koha::SFTP::Servers' } ); - - $sftp_server->update_password('test123'); - - my $sftp_server_plain_text_password = $sftp_server->plain_text_password; - - isnt( $sftp_server_plain_text_password, $sftp_server->password, 'Password and password hash shouldn\'t match' ); - is( $sftp_server_plain_text_password, 'test123', 'Password should be in plain text' ); - - $schema->storage->txn_rollback; -}; - -subtest 'plain_text_key() tests' => sub { - - plan tests => 2; - - $schema->storage->txn_begin; - - my $sftp_server = $builder->build_object( { class => 'Koha::SFTP::Servers' } ); - - $sftp_server->update_key_file('321tset'); - - my $sftp_server_plain_text_key = $sftp_server->plain_text_key; - - isnt( $sftp_server_plain_text_key, $sftp_server->key_file, 'Key file and key file hash shouldn\'t match' ); - is( $sftp_server_plain_text_key, "321tset\n", 'Key file should be in plain text' ); - - $schema->storage->txn_rollback; -}; - -subtest 'write_key_file() tests' => sub { - - plan tests => 3; - - $schema->storage->txn_begin; - - my $sftp_server = $builder->build_object( { class => 'Koha::SFTP::Servers' } ); - - $sftp_server->update_key_file('321tset'); - - my $path = '/tmp/kohadev_test'; - t::lib::Mocks::mock_config( 'upload_path', $path ); - mkdir $path if !-d $path; - - my $first_test = $sftp_server->write_key_file; - - my $file = $sftp_server->locate_key_file; - my $second_test = ( -f $file ); - - open( my $fh, '<', $sftp_server->locate_key_file ); - my $third_test = <$fh>; - - is( $first_test, 1, 'Writing key file should return 1' ); - is( $second_test, 1, 'Written key file should exist' ); - is( $third_test, "321tset\n", 'The contents of the key file should be 321tset\n' ); - - unlink $file; - - $schema->storage->txn_rollback; -}; diff --git a/t/db_dependent/api/v1/sftp_servers.t b/t/db_dependent/api/v1/sftp_servers.t index 4796a6afe16..80e6faea0f3 100755 --- a/t/db_dependent/api/v1/sftp_servers.t +++ b/t/db_dependent/api/v1/sftp_servers.t @@ -23,7 +23,6 @@ use Test::Mojo; use t::lib::TestBuilder; use t::lib::Mocks; -use Koha::SFTP::Servers; use Koha::Database; my $schema = Koha::Database->new->schema; @@ -38,7 +37,7 @@ subtest 'list() tests' => sub { $schema->storage->txn_begin; - Koha::SFTP::Servers->search->delete; + Koha::File::Transports->search->delete; my $librarian = $builder->build_object( { @@ -66,7 +65,7 @@ subtest 'list() tests' => sub { my $sftp_server = $builder->build_object( { - class => 'Koha::SFTP::Servers', + class => 'Koha::File::Transports', value => { password => undef, key_file => undef, @@ -80,7 +79,7 @@ subtest 'list() tests' => sub { my $another_sftp_server = $builder->build_object( { - class => 'Koha::SFTP::Servers', + class => 'Koha::File::Transports', value => { password => undef, key_file => undef, @@ -107,7 +106,7 @@ subtest 'get() tests' => sub { my $sftp_server = $builder->build_object( { - class => 'Koha::SFTP::Servers', + class => 'Koha::File::Transports', value => { password => undef, key_file => undef, @@ -142,7 +141,7 @@ subtest 'get() tests' => sub { my $sftp_server_to_delete = $builder->build_object( { - class => 'Koha::SFTP::Servers', + class => 'Koha::File::Transports', value => { password => undef, key_file => undef, @@ -165,7 +164,7 @@ subtest 'add() tests' => sub { $schema->storage->txn_begin; - Koha::SFTP::Servers->search->delete; + Koha::File::Transports->search->delete; my $librarian = $builder->build_object( { @@ -189,7 +188,7 @@ subtest 'add() tests' => sub { my $sftp_server = $builder->build_object( { - class => 'Koha::SFTP::Servers', + class => 'Koha::File::Transports', value => { password => undef, key_file => undef, @@ -276,7 +275,7 @@ subtest 'update() tests' => sub { my $sftp_server_id = $builder->build_object( { - class => 'Koha::SFTP::Servers', + class => 'Koha::File::Transports', value => { password => undef, key_file => undef, @@ -328,7 +327,7 @@ subtest 'update() tests' => sub { my $sftp_server_to_delete = $builder->build_object( { - class => 'Koha::SFTP::Servers', + class => 'Koha::File::Transports', value => { password => undef, key_file => undef, @@ -381,7 +380,7 @@ subtest 'delete() tests' => sub { my $sftp_server_id = $builder->build_object( { - class => 'Koha::SFTP::Servers', + class => 'Koha::File::Transports', value => { password => undef, key_file => undef, @@ -429,7 +428,7 @@ subtest 'test() tests' => sub { my $sftp_server = $builder->build_object( { - class => 'Koha::SFTP::Servers', + class => 'Koha::File::Transports', value => { password => undef, key_file => undef, -- 2.49.0