]> git.ipfire.org Git - thirdparty/public-inbox.git/commitdiff
www: load CSS files in same dir if @import is in use
authorEric Wong <e@80x24.org>
Thu, 26 Sep 2024 00:55:03 +0000 (00:55 +0000)
committerEric Wong <e@80x24.org>
Sat, 28 Sep 2024 20:39:03 +0000 (20:39 +0000)
In case user-supplied CSS uses @import statements, load any
other unspecified CSS files in that directory to ensure they can
be accessed by clients.

lib/PublicInbox/WWW.pm

index 6f7c30b9306aa5a2a28705eed10d40b602d178f3..65f95eb858a7faf5c78008bd84f07d88e1b93308 100644 (file)
@@ -13,6 +13,7 @@
 package PublicInbox::WWW;
 use strict;
 use v5.10.1;
+use autodie qw(chdir opendir);
 use PublicInbox::Config;
 use PublicInbox::Git;
 use PublicInbox::Hval;
@@ -593,6 +594,7 @@ sub stylesheets_prepare ($$) {
        my $stylesheets = $self->{pi_cfg}->{css} || [];
        my $links = [];
        my $inline_ok = 1;
+       my (%css_dir, @css_dir);
 
        foreach my $s (@$stylesheets) {
                my $attr = {};
@@ -606,8 +608,9 @@ sub stylesheets_prepare ($$) {
                if (defined $attr->{href}) {
                        $inline_ok = 0;
                } else {
-                       my $fn = $_;
-                       my ($key) = (m!([^/]+?)(?:\.css)?\z!i);
+                       my ($fn, $dir, $key);
+                       $fn = $_;
+                       ($dir, $key) = (m!\A(?:(.+?)/)?([^/]+?)(?:\.css)?\z!i);
                        if ($key !~ /\A[a-zA-Z0-9_\-\.]+\z/) {
                                warn "ignoring $fn, non-ASCII word character\n";
                                next;
@@ -617,6 +620,8 @@ sub stylesheets_prepare ($$) {
                                ($local, $ctime) = @$rec;
                        } elsif (open(my $fh, '<', $fn)) {
                                ($local, $ctime) = _read_css $fh, $mini, $fn;
+                               $local =~ /\@import\b/ && !$css_dir{$dir}++ and
+                                       push @css_dir, $dir;
                                $css_map->{$key} = [ $local, $ctime ];
                        } else {
                                warn "failed to open $fn: $!\n";
@@ -661,6 +666,31 @@ sub stylesheets_prepare ($$) {
        } else {
                $self->{-style_inline} = $buf;
        }
+       # load potentially imported CSS files in known CSS directories
+       if (@css_dir && !$self->{-css_dir}) {
+               opendir my $cwddh, '.';
+               for my $d (@css_dir) {
+                       CORE::opendir my $dh, $d or do {
+                               warn "W: opendir($d): $!";
+                               next;
+                       };
+                       chdir $dh;
+                       my @css = grep /\.css\z/i, readdir $dh;
+                       for my $fn (@css) {
+                               my ($key) = ($fn =~ m!([^/]+?)(?:\.css)?\z!i);
+                               next if $css_map->{$key};
+                               -f $fn or next;
+                               # no warning for autoloaded CSS
+                               open my $fh, '<', $fn or next;
+                               -T $fh or next;
+                               my ($local, $ctime) =
+                                               _read_css $fh, $mini, "$d/$fn";
+                               $css_map->{$key} = [ $local, $ctime ];
+                       }
+                       chdir $cwddh;
+               }
+               $self->{-css_dir} = \@css_dir;
+       }
        $css_map;
 }