HEX
Server: Apache/2.4.65 (Debian)
System: Linux kubikelcreative 5.10.0-35-amd64 #1 SMP Debian 5.10.237-1 (2025-05-19) x86_64
User: www-data (33)
PHP: 8.4.13
Disabled: NONE
Upload Files
File: //usr/local/usermin-1.750/authentic-theme/extensions/file-manager/file-manager-lib.pm
#
# Authentic Theme (https://github.com/authentic-theme/authentic-theme)
# Copyright Ilia Rostovtsev <programming@rostovtsev.io>
# Copyright Alexandr Bezenkov (https://github.com/real-gecko/filemin)
# Licensed under MIT (https://github.com/authentic-theme/authentic-theme/blob/master/LICENSE)
#
use strict;

use File::Basename;
use lib (dirname(__FILE__) . '/../../lib');

use Cwd 'abs_path';
use Encode qw(decode encode);
use File::MimeInfo;
use POSIX;

our (%access, %in, %text, @remote_user_info, $base_remote_user, $current_theme,
     %userconfig, @allowed_paths, @list, $base, $cwd, $path);
our $checked_path;

our %request_uri = get_request_uri();
set_module($request_uri{'module'});
get_libs($request_uri{'module'});

sub set_module
{
    my ($module) = @_;
    set_env('foreign_module_name', $module);
    set_env('foreign_root_directory', (get_env('document_root') . '/' . $module));
}

sub get_libs
{
    my ($module) = @_;

    require(get_env('document_root') . '/' . $module . '/' . $module . '-lib.pl');

    &ReadParse();

    get_paths();

    switch_to_user($in{'username'});

    $checked_path = $path;
    if (join(" , ", @allowed_paths) ne '/') {
        $checked_path =~ s/$in{'cwd'}\//\//ig;
    }

    %text = (load_language($current_theme), load_language($module), %text);
}

sub get_type
{
    my ($dir) = @_;
    if (-d $dir) {
        return 1;
    } else {
        return 0;
    }
}

sub get_errors
{
    my %errors = %{ $_[0] };

    if (scalar %errors) {
        return convert_to_json(\%errors);
    } else {
        return undef;
    }

}

sub get_request_uri
{
    (my $uri = get_env('request_uri')) =~ s/\?/&/;
    my @r = split /&/, $uri;
    my %c;

    foreach (@r) {
        my ($k, $v) = split /=/, $_;
        $c{$k} = $v;
    }

    return %c;
}

sub get_tree
{
    my ($p, $d, $e) = @_;
    my $df = int($d);
    my %r;
    my @r;

    my $wanted = sub {
        my $td = $File::Find::name;
        if (-d $td && !-l $td) {
            $td =~ s|^\Q$p\E/?||;
            if ($r{$td} || !$td) {
                return;
            }
            my ($pd, $cd) = $td =~ m|^ (.+) / ([^/]+) \z|x;
            my $pp = $p ne '/' ? $p : undef;
            my $c = $r{$td} =
              { key => html_escape("$pp/$td"), title => (defined($cd) ? html_escape($cd) : html_escape($td)) };
            defined $pd ? (push @{ $r{$pd}{children} }, $c) : (push @r, $c);
        }
    };
    my $preprocess = sub {
        my $td = $File::Find::name;
        my $d  = $td =~ tr[/][];

        if ($e && $p eq "/" && $d == 1) {
            if ($td =~ /^\/(cdrom|dev|lib|lost\+found|mnt|proc|run|snaps|sys|tmp|.trash)/i) {
                return;
            }
        }
        my $dd = ($df > 0 ? ($df + 1) : 0);
        if ($dd) {
            if ($d < $dd) {
                return sort @_;
            }
            return;
        }
        sort @_;
    };
    find(
         {  wanted     => $wanted,
            preprocess => $preprocess
         },
         $p);
    return \@r;
}

sub head
{
    print "Content-type: text/html\n\n";
}

sub set_response
{
    my ($c) = @_;
    print "Set-Cookie: file-manager-response=" . $c . "; path=/\r\n";
}

sub set_response_count
{
    my ($c) = @_;
    print "Set-Cookie: file-manager-response_count=" . $c . "; path=/\r\n";
}

sub fatal_errors
{
    my @errors = @_;

    head();
    print $text{'errors_occured'};
    print "<ul>";
    foreach my $error (@errors) {
        print("<li>$error</li>");
    }
    print "</ul>";
}

sub print_error
{
    my ($error) = @_;

    head();
    print $error;
    exit;

}

sub print_content
{
    my $setype = get_selinux_command_type();
    my %secontext;
    my %attributes;

    # Filter out not allowed entries
    if ($remote_user_info[0] ne 'root' && $allowed_paths[0] ne '$ROOT') {

        # Leave only allowed
        my @tmp_list;
        for $path (@allowed_paths) {
            my $slashed = $path;
            $slashed .= "/" if ($slashed !~ /\/$/);
            push @tmp_list, grep {$slashed =~ /^$_\// || $_ =~ /$slashed/} @list;
        }

        # Remove duplicates
        my %hash = map {$_, 1} @tmp_list;
        @list = keys %hash;
    }

    # List attributes
    if ($userconfig{'columns'} =~ /attributes/ && get_attr_status()) {
        my $command =
          get_attr_command() . join(' ', map {quotemeta("$_")} @list);
        my $output = `$command`;
        my @attributesArr =
          map {[split(/\s+/, $_, 2)]} split(/\n/, $output);
        %attributes = map {$_->[1] => ('<span data-attributes="s">' . $_->[0] . '</span>')} @attributesArr;
    }

    # List security context
    if ($userconfig{'columns'} =~ /selinux/ && get_selinux_status()) {
        my $command =
          get_selinux_command() . join(' ', map {quotemeta("$_")} @list);
        my $output = `$command`;
        (!$setype && ($output =~ s/\n//g, $output =~ s/,\s/,/g));
        my $delimiter = ($setype ? '\n' : ',');
        my @searray =
          map {[split(/\s+/, $_, 2)]} split(/$delimiter/, $output);
        %secontext =
          map {$_->[1] => ($_->[0] eq "?" ? undef : ('<span data-secontext>' . $_->[0] . '</span>'))} @searray;
    }

    # Get info about directory entries
    my @info = map {[$_, lstat($_), &mimetype($_), -d, -l $_, $secontext{$_}, $attributes{$_}]} @list;

    # Filter out folders
    my @folders = map {$_} grep {$_->[15] == 1} @info;

    # Filter out files
    my @files = map {$_} grep {$_->[15] != 1} @info;

    # Sort stuff by name
    @folders = sort {$a->[0] cmp $b->[0]} @folders;
    @files   = sort {$a->[0] cmp $b->[0]} @files;

    # Recreate list
    undef(@list);
    push @list, @folders, @files;

    my @allowed_for_edit = split(/\s+/, $access{'allowed_for_edit'});
    my %allowed_for_edit = map {$_ => 1} @allowed_for_edit;

    # Set icons variables
    my $edit_icon    = "<i class='fa fa-edit' alt='$text{'edit'}'></i>";
    my $rename_icon  = "<i class='fa fa-font' title='$text{'rename'}'></i>";
    my $extract_icon = "<i class='fa fa-external-link' alt='$text{'extract_archive'}'></i>";
    my $goto_icon    = "<i class='fa fa-arrow-right' alt='$text{'goto_folder'}'></i>";

    my $page      = 1;
    my $pagelimit = 4294967295;

    my $info_total;
    my $info_files   = scalar @files;
    my $info_folders = scalar @folders;

    if ($info_files eq 1 && $info_folders eq 1) {
        $info_total = 'filemanager_global_info_total1';
    } elsif ($info_files ne 1 && $info_folders eq 1) {
        $info_total = 'filemanager_global_info_total2';
    } elsif ($info_files eq 1 && $info_folders ne 1) {
        $info_total = 'filemanager_global_info_total3';
    } else {
        $info_total = 'filemanager_global_info_total4';
    }

    head();
    print '<!DOCTYPE html>';
    print '<html>';
    print '<head></head>';
    print '<body>';
    print "<div class='total'>" . text($info_total, $info_files, $info_folders) . "</div>";

    # Render current directory entries
    print &ui_form_start("", "post", undef, "id='list_form'");
    my @ui_columns = ('<input class="_select-unselect_" type="checkbox" onclick="selectUnselect(this)" />', '');
    push @ui_columns, ('<span data-head-name>' . $text{'name'} . '</span>');
    push @ui_columns, ('<span data-head-type>' . $text{'type'} . '</span>')
      if ($userconfig{'columns'} =~ /type/);
    push @ui_columns, ('<span data-head-actions>' . $text{'actions'} . '</span>');
    push @ui_columns, ('<span data-head-size>' . $text{'size'} . '</span>')
      if ($userconfig{'columns'} =~ /size/);
    push @ui_columns, ('<span data-head-owner_user>' . $text{'ownership'} . '</span>')
      if ($userconfig{'columns'} =~ /owner_user/);
    push @ui_columns, ('<span data-head-permissions>' . $text{'permissions'} . '</span>')
      if ($userconfig{'columns'} =~ /permissions/);
    push @ui_columns, ('<span data-head-attributes>' . $text{'attributes'} . '</span>')
      if (get_attr_status() && $userconfig{'columns'} =~ /attributes/);
    push @ui_columns, ('<span data-head-selinux>' . $text{'selinux'} . '</span>')
      if (get_selinux_status() && $userconfig{'columns'} =~ /selinux/);
    push @ui_columns, ('<span data-head-last_mod_time>' . $text{'last_mod_time'} . '</span>')
      if ($userconfig{'columns'} =~ /last_mod_time/);

    print &ui_columns_start(\@ui_columns);
    for (my $count = 1 + $pagelimit * ($page - 1); $count <= $pagelimit + $pagelimit * ($page - 1); $count++) {
        if ($count > scalar(@list)) {last;}
        my $class = $count & 1 ? "odd" : "even";
        my $link = $list[$count - 1][0];
        $link =~ s/\Q$cwd\E\///;
        $link =~ s/^\///g;
        my $vlink = html_escape($link);
        $vlink = decode('UTF-8', $vlink, Encode::FB_DEFAULT);
        my $hlink = html_escape($vlink);
        $path = html_escape($path);

        my $type = $list[$count - 1][14];
        $type =~ s/\//\-/g;
        my $img = "images/icons/mime/$type.png";
        unless (-e $request_uri{'module'} . '/' . $img) {
            $img = "images/icons/mime/unknown.png";
        }
        my $size = &local_nice_size($list[$count - 1][8]);
        my $user;
        my $group;
        if (supports_users()) {
            my $uid = getpwuid($list[$count - 1][5]);
            my $gid = getgrgid($list[$count - 1][6]);
            $user  = $uid ? $uid : $list[$count - 1][5];
            $group = $gid ? $gid : $list[$count - 1][6];
        } else {
            $user  = $list[$count - 1][5];
            $group = $list[$count - 1][6];
        }

        my $permissions = sprintf("%04o", $list[$count - 1][3] & 07777);
        my $selinux;
        if (get_selinux_status() && $userconfig{'columns'} =~ /selinux/) {
            $selinux = $list[$count - 1][17];
        }

        my $attributes;
        if (get_attr_status() && $userconfig{'columns'} =~ /attributes/) {
            $attributes = $list[$count - 1][18];
        }

        my $mod_time = POSIX::strftime('%Y/%m/%d - %T', localtime($list[$count - 1][10]));

        my $actions =
"<a class='action-link' href='javascript:void(0)' onclick='renameDialog(\"$hlink\")' title='$text{'rename'}' data-container='body'>$rename_icon</a>";
        my $href;
        if ($list[$count - 1][15] == 1) {
            if ($path eq '/' . $link) {
                $href = "index.cgi?path=" . &urlize("$path");
            } else {
                $href = "index.cgi?path=" . &urlize("$path/$link");
            }
        } else {
            my ($fname, $fpath, $fsuffix) =
              fileparse($list[$count - 1][0]);
            if ($base ne '/') {
                $fpath =~ s/^\Q$base\E//g;
            }
            $href = "download.cgi?file=" . &urlize($link) . "&path=" . &urlize($fpath);
            if ($0 =~ /search.cgi/) {
                $actions =
                  "$actions<a class='action-link' " .
                  "href='index.cgi?path=" . &urlize($fpath) . "' " . "title='$text{'goto_folder'}'>$goto_icon</a>";
            }
            if ($type =~ /text-/ or
                exists($allowed_for_edit{$type}))
            {
                $actions =
                  "$actions<a class='action-link' href='edit_file.cgi?file=" . &urlize($link) .
                  "&path=" . &urlize($path) . "' title='$text{'edit'}' data-container='body'>$edit_icon</a>";
            }
            if (($type =~ /application-zip/ && has_command('unzip')) ||
                ($type =~ /application-x-7z-compressed/ &&
                    has_command('7z')) ||
                ($type =~ /application-x-rar|application-vnd\.rar/ &&
                    has_command('unrar')) ||
                ($type =~ /application-x-rpm/ &&
                    has_command('rpm2cpio') &&
                    has_command('cpio')) ||
                ($type =~ /application-x-deb/ &&
                    has_command('dpkg'))
                ||
                (
                    ($type =~ /x-compressed-tar/ || $type =~ /-x-tar/ ||
                     ($type =~ /-x-bzip/ &&
                         has_command('bzip2')) ||
                     ($type =~ /-gzip/ &&
                         has_command('gzip')) ||
                     ($type =~ /-x-xz/ &&
                         has_command('xz'))
                    ) &&
                    has_command('tar')))
            {
                $actions =
                  "$actions <a class='action-link' href='extract.cgi?path=" . &urlize($path) .
                  "&file=" . &urlize($link) . "' title='$text{'extract_archive'}' data-container='body'>$extract_icon</a> ";
            }
        }
        my @row_data =
          ("<a href='$href'><img src=\"$img\"></a>", "<a href=\"$href\" data-filemin-link=\"$hlink\">$vlink</a>");
        push @row_data, $type if ($userconfig{'columns'} =~ /type/);
        push @row_data, $actions;
        push @row_data, $size if ($userconfig{'columns'} =~ /size/);
        push @row_data, $user . ':' . $group
          if ($userconfig{'columns'} =~ /owner_user/);
        push @row_data, $permissions
          if ($userconfig{'columns'} =~ /permissions/);
        push @row_data, $attributes
          if (get_attr_status() && $userconfig{'columns'} =~ /attributes/);
        push @row_data, $selinux
          if (get_selinux_status() && $userconfig{'columns'} =~ /selinux/);
        push @row_data, $mod_time
          if ($userconfig{'columns'} =~ /last_mod_time/);
        print &ui_checked_columns_row(\@row_data, "", "name", $vlink);
    }
    print ui_columns_end();
    print &ui_hidden("path", $path), "\n";
    print '</form>';
    print '<div class="error_message">' . $in{'error'} . '</div>'
      if (length $in{'error'});
    print '<div class="error_fatal">' . $in{'error_fatal'} . '</div>'
      if (length $in{'error_fatal'});
    print '</body>';
    print '</html>';

}

sub local_nice_size
{
    # my %text = (load_language($current_theme), %text);
    my ($units, $uname);
    if (abs($_[0]) > 1024 * 1024 * 1024 * 1024 * 1024 || $_[1] >= 1024 * 1024 * 1024 * 1024 * 1024) {
        $units = 1024 * 1024 * 1024 * 1024 * 1024;
        $uname = $text{'theme_nice_size_PB'};
    } elsif (abs($_[0]) > 1024 * 1024 * 1024 * 1024 || $_[1] >= 1024 * 1024 * 1024 * 1024) {
        $units = 1024 * 1024 * 1024 * 1024;
        $uname = $text{'theme_nice_size_TB'};
    } elsif (abs($_[0]) > 1024 * 1024 * 1024 || $_[1] >= 1024 * 1024 * 1024) {
        $units = 1024 * 1024 * 1024;
        $uname = $text{'theme_nice_size_GB'};
    } elsif (abs($_[0]) > 1024 * 1024 || $_[1] >= 1024 * 1024) {
        $units = 1024 * 1024;
        $uname = $text{'theme_nice_size_MB'};
    } elsif (abs($_[0]) > 1024 || $_[1] >= 1024) {
        $units = 1024;
        $uname = $text{'theme_nice_size_kB'};
    } else {
        $units = 1;
        $uname = $text{'theme_nice_size_b'};
    }
    my $sz = sprintf("%.2f", ($_[0] * 1.0 / $units));
    $sz =~ s/\.00$//;
    return '<span data-filesize-bytes="' . $_[0] . '">' . ($sz . " " . $uname) . '</span>';
}

sub paster
{
    my ($c, $f, $s, $d, $r, $m) = @_;
    my $x;
    my $j = $c . '/' . $f;
    if (!$r && -f $j ne -d $j) {
        for (my $t = 1;; $t += 1) {
            if (!-e ($j . '(' . $t . ')')) {
                $x = $t;
                last;
            }
        }
    }
    if ($m && $j =~ /\Q$s\E/) {
        set_response('merr');
        return;
    }
    my ($o, $e) = copy_source_dest($s, $j . (!$x ? '' : '(' . $x . ')'));
    if ($x) {
        set_response('cc');
    }
    if ($m) {
        unlink_file($s);
    }

    return $e;

}

sub switch_to_user
{
    if (!supports_users()) {
        return undef;
    }
    my ($username) = @_;
    my @uinfo = getpwnam($username);
    if (@uinfo) {
        switch_to_unix_user(\@uinfo);
    }

}

sub is_root
{
    return ($base_remote_user eq 'root' ? 1 : 0);
}

sub get_env
{
    my ($key) = @_;
    return $ENV{ uc($key) };
}

sub set_env
{
    my ($k, $v) = @_;
    $ENV{ uc($k) } = $v;
}

sub trim
{
    my $s = shift;
    $s =~ s/^\s+|\s+$//g;
    return $s;
}

1;