Bug 39190: Remove old objects

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
Martin Renvoize 2025-02-14 16:22:35 +00:00 committed by Lucas Gass
parent b701fed04c
commit a5acb762ee
No known key found for this signature in database
GPG Key ID: 60B447398B0D36CA
5 changed files with 11 additions and 711 deletions

View File

@ -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 <http://www.gnu.org/licenses>.
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;

View File

@ -1,85 +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 <http://www.gnu.org/licenses>.
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 _polymorphic_field
Return the field in the table that defines the polymorphic class to be built
=cut
sub _polymorphic_field {
return 'transport'; # This field defines which subclass to use
}
=head3 _polymorphic_map
Return the mapping for field value to class name for the polymorphic class
=cut
sub _polymorphic_map {
return {
sftp => 'Koha::File::Transport::SFTP',
ftp => 'Koha::File::Transport::FTP',
};
}
=head3 object_class
Return object class
=cut
sub object_class {
my ( $self, $object ) = @_;
return 'Koha::File::Transport' unless $object;
my $field = $self->_polymorphic_field;
my $map = $self->_polymorphic_map;
return $map->{ lc( $object->$field ) } || 'Koha::File::Transport';
}
1;

View File

@ -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;

View File

@ -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 <http://www.gnu.org/licenses>.
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;
};

View File

@ -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,