Improve handling of non-existing or malformed JSON conf-files
Change-Id: Ia89be3459d60a11302ddd18a0c57a01b38996137
diff --git a/.gitignore b/.gitignore
index 5818b15..dfb29e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,11 +1,13 @@
/cache
/kalamar.secret*
+super_client_info
/start-test
/todo.org
/fixtures.txt
/sandbox
/Sandbox
-/node_modules
+node_modules
+/local/
/cache/data
/public
/kalamar.*.conf
diff --git a/Changes b/Changes
index 970fc6d..59f97fc 100644
--- a/Changes
+++ b/Changes
@@ -1,6 +1,8 @@
- Expose colors and forms to plugins (diewald)
- Support additional activity-toggle in buttons (diewald)
- Authorization service with POST (support API version 1.1) (hebasta)
+ - Enhance handling of improper json files (diewald)
+ - Support API version 1.1 (diewald)
0.64 2026-02-14
- Improve 'Plugins' mounting (diewald)
diff --git a/lib/Kalamar/Plugin/Auth.pm b/lib/Kalamar/Plugin/Auth.pm
index cf06321..a2154c2 100644
--- a/lib/Kalamar/Plugin/Auth.pm
+++ b/lib/Kalamar/Plugin/Auth.pm
@@ -56,9 +56,27 @@
# Get client_id and client_secret from client file
if ($param->{client_file} || $main::ENV{KALAMAR_CLIENT_FILE}) {
$param->{client_file} ||= $main::ENV{KALAMAR_CLIENT_FILE};
- my $client_json = decode_json(path($param->{client_file})->slurp);
- $param->{client_id} //= $client_json->{client_id};
- $param->{client_secret} //= $client_json->{client_secret};
+
+ # Load client file
+ if (-e $param->{client_file}) {
+ my $client_file = path($param->{client_file})->slurp;
+
+ eval {
+ my $client_json = decode_json($client_file);
+
+ if ($client_json) {
+ $param->{client_id} //= $client_json->{client_id};
+ $param->{client_secret} //= $client_json->{client_secret};
+ }
+ };
+
+ if ($@) {
+ $app->log->error('provided client file syntax invalid:' . $param->{client_file} . '; ' . $@);
+ };
+ }
+ else {
+ $app->log->error('provided client file does not exist: ' . $param->{client_file});
+ };
};
# Get the client id and the client_secret as a requirement
diff --git a/lib/Kalamar/Plugin/Plugins.pm b/lib/Kalamar/Plugin/Plugins.pm
index a2a81d3..17dee1b 100644
--- a/lib/Kalamar/Plugin/Plugins.pm
+++ b/lib/Kalamar/Plugin/Plugins.pm
@@ -21,12 +21,23 @@
if ($param->{default_file}) {
# Read default plugins file
+ unless (-e $param->{default_file}) {
+ $app->log->error('provided default_plugins file does not exist: ' . $param->{default_file});
+ return;
+ };
+
my $default = path($param->{default_file});
# Use correct working directory
$default = $app->home->child($default) unless $default->is_abs;
- @json_array = @{ decode_json $default->slurp };
+ eval {
+ @json_array = @{ decode_json $default->slurp };
+ };
+
+ if ($@) {
+ $app->log->error('provided plugin file syntax invalid:' . $param->{default_file} . '; ' . $@);
+ };
};
# There are default plugins to be registered
diff --git a/t/plugin/auth-oauth.t b/t/plugin/auth-oauth.t
index 04fcc3c..f83bd2a 100644
--- a/t/plugin/auth-oauth.t
+++ b/t/plugin/auth-oauth.t
@@ -507,14 +507,11 @@
->header_is('Pragma','no-cache')
;
-my $loglines = '';
-$t->app->log->on(
- message => sub {
- my ($log, $level, @lines) = @_;
- if ($level eq 'warn') {
- $loglines = join ',', @lines;
- };
- });
+
+my $log_output = '';
+open my $log_fh, '>', \$log_output or die $!;
+$t->app->log->handle($log_fh);
+$t->app->log->level('warn');
$t->get_ok('/settings/marketplace')
->status_is(200)
@@ -523,7 +520,7 @@
->element_exists_not('ul.plugin_in-list')
;
-is($loglines, '', 'Check log is fine');
+is($log_output, '', 'Check log is fine');
$csrf = $t->post_ok('/settings/oauth/register' => form => {
name => 'MyApp',
@@ -1382,7 +1379,43 @@
->element_exists('aside.settings')
;
+$log_output = '';
+# Test non-existing client file (app should initialize without crashing)
+$t = Test::Mojo->new('Kalamar');
+$t->app->log->handle($log_fh);
+$t->app->log->level('error');
+$t->app->plugin('Mount' => {
+ $mount_point => $fixtures_path->child('mock.pl')
+});
+
+$t->app->plugin('Auth' => {
+ client_file => '/nonexistent/client.json',
+ oauth2 => 1
+ }
+);
+ok($t->app, 'App initializes with non-existing client file');
+like($log_output, qr'provided client file does not exist', 'Check log is fine');
+
+$log_output = '';
+
+# Test malformed JSON client file (app should initialize without crashing)
+my $bad_client_file = tempfile();
+$bad_client_file->spew('{invalid json}');
+$t = Test::Mojo->new('Kalamar');
+$t->app->log->handle($log_fh);
+$t->app->log->level('error');
+$t->app->plugin('Mount' => {
+ $mount_point => $fixtures_path->child('mock.pl')
+});
+
+$t->app->plugin('Auth' => {
+ client_file => $bad_client_file->to_string,
+ oauth2 => 1
+ }
+);
+ok($t->app, 'App initializes with malformed JSON client file');
+like($log_output, qr'provided client file syntax invalid', 'Check log is fine');
done_testing;
__END__
diff --git a/t/plugin/plugins.t b/t/plugin/plugins.t
index 93ebc29..d68730e 100644
--- a/t/plugin/plugins.t
+++ b/t/plugin/plugins.t
@@ -69,4 +69,28 @@
->json_is('/1/embed/0/title','Full Text')
;
+# Test non-existing file
+my $t2 = Test::Mojo->new('Kalamar');
+my $log_output = '';
+open my $log_fh, '>', \$log_output or die $!;
+$t2->app->log->handle($log_fh);
+$t2->app->log->level('error');
+$t2->app->plugin('Plugins' => {
+ default_plugins => '/nonexistent/file.json'
+});
+like($log_output, qr/provided default_plugins file does not exist/, 'Non-existing file logged');
+
+# Test malformed JSON
+$log_output = '';
+my $t3 = Test::Mojo->new('Kalamar');
+my $bad_json = tempfile();
+$bad_json->spew('{invalid json}');
+#$t3->app->log->level('error');
+$t3->app->log->handle($log_fh);
+$t3->app->log->level('error');
+$t3->app->plugin('Plugins' => {
+ default_plugins => $bad_json->to_string
+});
+like($log_output, qr/provided plugin file syntax invalid/, 'Malformed JSON logged');
+
done_testing;