Brian Read
a428e91c92
- Add mojo logo to footer [SME: 12679] - Fix default for HeaderWeight to avoid noise in logs if no Nav header in file - Align buttons consistently [SME: 12680]
860 lines
26 KiB
Perl
860 lines
26 KiB
Perl
# SrvMngr: a web-based Sme Koozali server administration GUI
|
|
package SrvMngr;
|
|
|
|
use strict;
|
|
use warnings;
|
|
use utf8;
|
|
|
|
use Mojo::Base 'Mojolicious';
|
|
|
|
use File::Spec;
|
|
use File::Spec::Functions qw( rel2abs catdir );
|
|
use Cwd;
|
|
use Net::Netmask;
|
|
|
|
use Mojo::File qw( path );
|
|
use Mojo::Home;
|
|
|
|
use DBM::Deep;
|
|
use Mojo::JWT;
|
|
|
|
use Mojolicious::Plugin::Config;
|
|
#use Mojolicious::Plugin::I18N;
|
|
|
|
use SrvMngr::Plugin::I18N;
|
|
use SrvMngr::I18N;
|
|
use SrvMngr::Model::Main;
|
|
|
|
|
|
our $VERSION = '1.420';
|
|
$VERSION = eval $VERSION;
|
|
|
|
use Exporter 'import';
|
|
our @EXPORT_OK = qw(
|
|
init_session get_mod_url theme_list
|
|
getNavigation ip_number is_normal_password email_simple
|
|
mac_address_or_blank mac_address ip_number_or_blank
|
|
lang_space get_routes_list subnet_mask get_reg_mask
|
|
);
|
|
|
|
has home => sub {
|
|
my $path = $ENV{SRVMNGR_HOME} || getcwd;
|
|
return Mojo::Home->new(File::Spec->rel2abs($path));
|
|
};
|
|
|
|
has config_file => sub {
|
|
my $self = shift;
|
|
return $ENV{SRVMNGR_CONFIG} if $ENV{SRVMNGR_CONFIG};
|
|
return $self->home->rel_file('conf/srvmngr.conf');
|
|
};
|
|
|
|
has data_dir => sub {
|
|
my $self = shift;
|
|
return $ENV{SRVMNGR_DATA} if $ENV{SRVMNGR_DATA};
|
|
return $self->home->rel_file('data');
|
|
};
|
|
|
|
has temp_dir => sub {
|
|
my $self = shift;
|
|
return $ENV{SRVMNGR_TEMP} if $ENV{SRVMNGR_TEMP};
|
|
return $self->home->rel_file('temp');
|
|
};
|
|
|
|
has conf_dir => sub{
|
|
my $self = shift;
|
|
return $ENV{SRVMNGR_CONF} if $ENV{SRVMNGR_CONF};
|
|
return $self->home->rel_file('conf');
|
|
};
|
|
|
|
|
|
sub startup {
|
|
|
|
my $self = shift;
|
|
|
|
$self->plugin( Config => { file => $self->config_file()} );
|
|
|
|
$self->mode( $self->config->{mode} || 'production' ); #'development'
|
|
|
|
$ENV{'MOJO_SMANAGER_DEBUG'} = $self->config->{debug} || 0;
|
|
|
|
$self->setup_plugins;
|
|
|
|
$self->setup_helpers;
|
|
|
|
$self->setup_paths;
|
|
|
|
$self->setup_sessions;
|
|
|
|
$self->setup_routing;
|
|
|
|
$self->setup_hooks;
|
|
|
|
# no data in cache
|
|
$self->renderer->cache->max_keys(0);
|
|
|
|
}
|
|
|
|
|
|
sub setup_sessions {
|
|
|
|
my $self = shift;
|
|
|
|
# Setup signed sessions
|
|
$self->app->secrets( $self->config->{secrets} );
|
|
$self->sessions->cookie_name('smanager');
|
|
$self->sessions->default_expiration( $self->config->{timeout} );
|
|
$self->sessions->secure( 1 );
|
|
|
|
}
|
|
|
|
|
|
sub setup_paths {
|
|
|
|
my $self = shift;
|
|
|
|
# Replace the default paths
|
|
$self->renderer->paths([$self->home->rel_file('themes/default/templates')]);
|
|
$self->static->paths([$self->home->rel_file('themes/default/public')]);
|
|
|
|
my $theme = $self->config->{theme} || 'default';
|
|
if ( $theme ne 'default' ) {
|
|
# Put the new theme first
|
|
my $t_path = $self->home->rel_file('themes/'.$theme);
|
|
unshift @{$self->renderer->paths}, $t_path.'/templates' if -d $t_path.'/templates';
|
|
unshift @{$self->static->paths}, $t_path.'/public' if -d $t_path.'/public';
|
|
}
|
|
|
|
}
|
|
|
|
|
|
sub setup_helpers {
|
|
|
|
my $self = shift;
|
|
|
|
$self->helper(log_req => sub {
|
|
my $c = shift;
|
|
my $mess = shift || '';
|
|
my $method = $c->req->method;
|
|
my $url = $c->req->url;
|
|
my $version = $c->req->version;
|
|
my $ip = $c->tx->remote_address;
|
|
return "Request received => $method $url HTTP/$version from $ip : $mess ";
|
|
});
|
|
|
|
$self->helper( 'home_page' => sub{ '/initial' } );
|
|
|
|
$self->helper( 'auth_fail' => sub {
|
|
my $self = shift;
|
|
my $message = shift || $self->l('acs_NO');
|
|
$self->flash( error => $message );
|
|
$self->redirect_to( $self->home_page, status => 403 );
|
|
return 0;
|
|
});
|
|
|
|
$self->helper( 'is_admin' => sub {
|
|
my $self = shift;
|
|
if ( defined $self->session->{username} && defined $self->session->{is_admin} ) {
|
|
return $self->session->{is_admin};
|
|
}
|
|
return undef;
|
|
});
|
|
|
|
$self->helper( 'is_unsafe' => sub {
|
|
return SrvMngr::Model::Main->reconf_needed();
|
|
});
|
|
|
|
$self->helper( 'is_logged_in' => sub {
|
|
my $self = shift;
|
|
if ( defined $self->session->{logged_in} ) {
|
|
return 1 if ( $self->session('logged_in') == 1 );
|
|
}
|
|
return undef;
|
|
});
|
|
|
|
$self->helper(lang_space => \&_lang_space);
|
|
|
|
$self->plugin( Config => { file => $self->config_file()} );
|
|
|
|
$self->helper( send_email => sub {
|
|
my ($c, $address, $subject, $body) = @_;
|
|
|
|
if (not defined $body) {
|
|
warn "send_email: Need 3 parameters (Address, Subject, Body)\n";
|
|
return;
|
|
}
|
|
|
|
my $rcfile = $c->app->conf_dir().'/admin_muttrc';
|
|
|
|
#warn "send_email: $rcfile * $address\n"; #$rcfile $subject $address\n";
|
|
system( "/bin/echo \"$body\" | /usr/bin/mutt -F $rcfile -s \"$subject\" \"$address\"" ) == 0
|
|
or warn "error sendmail: $address \n"; # $subject";
|
|
});
|
|
|
|
$self->helper( pwdrst => sub {
|
|
my $c = shift;
|
|
my $file = $c->app->data_dir().'/pwdrst.db';
|
|
state $db = DBM::Deep->new($file);
|
|
});
|
|
|
|
$self->helper( jwt => sub {
|
|
Mojo::JWT->new(secret => shift->app->secrets->[0] || die)
|
|
});
|
|
|
|
}
|
|
|
|
|
|
sub setup_plugins {
|
|
|
|
my $self = shift;
|
|
|
|
$self->plugin('TagHelpers');
|
|
|
|
$self->plugin('RenderFile');
|
|
|
|
# CSRF protection if production mode
|
|
# $self->plugin('Mojolicious::Plugin::CSRFDefender' => {
|
|
# Adapted plugin for use with GET method
|
|
$self->plugin('SrvMngr::Plugin::CSRFDefender' => {
|
|
onetime => 1,
|
|
error_status => 400,
|
|
error_content => 'Error: CSRF token is invalid or outdated'
|
|
#error_template => 'csrf_400'
|
|
}) if ( $self->mode eq 'production' );
|
|
|
|
$self->plugin('SrvMngr::Plugin::I18N' => {namespace => 'SrvMngr::I18N', default => 'en'});
|
|
|
|
# $self->plugin('Mojolicious::Plugin::FrozenSessions' => {});
|
|
|
|
$self->helper(log_req => sub {
|
|
|
|
my $c = shift;
|
|
my $mess = shift || '';
|
|
|
|
my $method = $c->req->method;
|
|
my $url = $c->req->url;
|
|
my $version = $c->req->version;
|
|
my $ip = $c->tx->remote_address;
|
|
|
|
return "Request received => $method $url HTTP/$version from $ip: $mess ";
|
|
});
|
|
}
|
|
|
|
|
|
sub setup_routing {
|
|
|
|
my $self = shift;
|
|
my $r = $self->app->routes;
|
|
$r->namespaces(['SrvMngr::Controller']);
|
|
|
|
$r->get('/')->to('initial#main')->name('initial');
|
|
$r->get('/initial')->to('initial#main')->name('initial');
|
|
$r->get('/login')->to('login#main')->name('login');
|
|
$r->post('/login')->to('login#login')->name('signin');
|
|
$r->get('/manual')->to('manual#main')->name('manual');
|
|
$r->get('/support')->to('support#main')->name('support');
|
|
|
|
# Password reset allowed for this server
|
|
if ( ( $self->config->{pwdreset} || '0') == 1 ) {
|
|
$r->get('/login2')->to('login#pwdrescue')->name('pwdresc');
|
|
$r->get('/loginc')->to('login#confpwd')->name('resetpwdconf');
|
|
$r->get('/userpasswordr')->to('userpassword#main')->name('upwdreset');
|
|
$r->post('/userpasswordr')->to('userpassword#change_password')->name('upwdreset2');
|
|
}
|
|
|
|
my $if_logged_in = $r->under( sub {
|
|
my $c =shift;
|
|
return $c->is_logged_in || $c->auth_fail($c->l("acs_LOGIN"));
|
|
});
|
|
$if_logged_in->post('/swttheme')->to('swttheme#main')->name('swttheme');
|
|
$if_logged_in->get('/review')->to('review#main')->name('review');
|
|
$if_logged_in->get('/logout')->to('logout#logout')->name('logout');
|
|
$if_logged_in->get('/userpassword')->to('userpassword#main')->name('passwd');
|
|
$if_logged_in->post('/userpassword')->to('userpassword#change_password')->name('passwd2');
|
|
|
|
my $if_admin = $r->under( sub {
|
|
my $c =shift;
|
|
return $c->is_admin || $c->auth_fail($c->l("acs_ADMIN"));
|
|
});
|
|
|
|
$if_admin->get('/backup')->to('backup#main')->name('backup');
|
|
$if_admin->post('/backup')->to('backup#do_display')->name('backupd');
|
|
$if_admin->get('/backupd')->to('backup#do_display')->name('backupc'); # corrections #
|
|
$if_admin->post('/backupd')->to('backup#do_update')->name('backupu');
|
|
|
|
$if_admin->get('/bugreport')->to('bugreport#main')->name('bugreport');
|
|
$if_admin->post('/bugreport')->to('bugreport#do_report')->name('bugreport2');
|
|
$if_admin->post('/bugreportD')->to('bugreport#download_config_report')->name('bugreportD');
|
|
|
|
$if_admin->get('/clamav')->to('clamav#main')->name('clamav');
|
|
$if_admin->post('/clamav')->to('clamav#do_update')->name('clamav2');
|
|
|
|
$if_admin->get('/datetime')->to('datetime#main')->name('datetime');
|
|
$if_admin->post('/datetime')->to('datetime#do_update')->name('datetime2');
|
|
|
|
$if_admin->get('/directory')->to('directory#main')->name('directory');
|
|
$if_admin->post('/directory')->to('directory#do_update')->name('directory2');
|
|
|
|
$if_admin->get('/domains')->to('domains#main')->name('domainsg');
|
|
$if_admin->post('/domains')->to('domains#do_display')->name('domainsp');
|
|
$if_admin->get('/domains2')->to('domains#do_display')->name('domains2g');
|
|
$if_admin->post('/domains2')->to('domains#do_update')->name('domains2p');
|
|
|
|
$if_admin->get('/emailsettings')->to('emailsettings#main')->name('emailsettings');
|
|
$if_admin->post('/emailsettings')->to('emailsettings#do_display')->name('emailsetting');
|
|
$if_admin->post('/emailsettingd')->to('emailsettings#do_update')->name('emailsettingu');
|
|
|
|
$if_admin->get('/groups')->to('groups#main')->name('groupsl');
|
|
$if_admin->post('/groups')->to('groups#do_display')->name('groupa');
|
|
$if_admin->get('/groups2')->to('groups#do_display')->name('groupd');
|
|
$if_admin->post('/groups2')->to('groups#do_update')->name('groupu');
|
|
|
|
$if_admin->get('/hostentries')->to('hostentries#main')->name('hostentries');
|
|
$if_admin->post('/hostentries')->to('hostentries#do_display')->name('hostentryadd');
|
|
$if_admin->get('/hostentriesd')->to('hostentries#do_display')->name('hostentrydis');
|
|
$if_admin->post('/hostentriesd')->to('hostentries#do_update')->name('hostentryupd');
|
|
|
|
$if_admin->get('/ibays')->to('ibays#main')->name('ibays');
|
|
$if_admin->post('/ibays')->to('ibays#do_display')->name('ibayadd');
|
|
$if_admin->get('/ibaysd')->to('ibays#do_display')->name('ibaydis');
|
|
$if_admin->post('/ibaysd')->to('ibays#do_update')->name('ibayupd');
|
|
|
|
$if_admin->get('/localnetworks')->to('localnetworks#main')->name('localnetworks');
|
|
$if_admin->post('/localnetworks')->to('localnetworks#do_display')->name('localnetworks');
|
|
$if_admin->post('/localnetworksa')->to('localnetworks#do_display')->name('localnetworksadd');
|
|
$if_admin->post('/localnetworksb')->to('localnetworks#do_display')->name('localnetworksadd1');
|
|
$if_admin->get('/localnetworksd')->to('localnetworks#do_display')->name('localnetworksdel');
|
|
$if_admin->post('/localnetworkse')->to('localnetworks#do_display')->name('localnetworksdel1');
|
|
|
|
$if_admin->get('/portforwarding')->to('portforwarding#main')->name('portforwarding');
|
|
$if_admin->post('/portforwarding')->to('portforwarding#do_display')->name('portforwarding');
|
|
$if_admin->post('/portforwardinga')->to('portforwarding#do_display')->name('portforwardingadd');
|
|
$if_admin->post('/portforwardingb')->to('portforwarding#do_display')->name('portforwardingadd1');
|
|
$if_admin->get('/portforwardingd')->to('portforwarding#do_display')->name('portforwardingdel');
|
|
$if_admin->post('/portforwardinge')->to('portforwarding#do_display')->name('portforwardingdel1');
|
|
|
|
$if_admin->get('/printers')->to('printers#main')->name('printersg');
|
|
$if_admin->post('/printers')->to('printers#do_display')->name('printera');
|
|
$if_admin->get('/printers2')->to('printers#do_display')->name('printer2g');
|
|
$if_admin->post('/printers2')->to('printers#do_update')->name('printers2p');
|
|
|
|
$if_admin->get('/proxy')->to('proxy#main')->name('proxy');
|
|
$if_admin->post('/proxy')->to('proxy#do_update')->name('proxy2');
|
|
|
|
$if_admin->get('/pseudonyms')->to('pseudonyms#main')->name('pseudonymsl');
|
|
$if_admin->post('/pseudonyms')->to('pseudonyms#do_display')->name('pseudonyma');
|
|
$if_admin->get('/pseudonyms2')->to('pseudonyms#do_display')->name('pseudonymd');
|
|
$if_admin->post('/pseudonyms2')->to('pseudonyms#do_update')->name('pseudonymu');
|
|
|
|
$if_admin->get('/qmailanalog')->to('qmailanalog#main')->name('qmailanalog');
|
|
$if_admin->post('/qmailanalog')->to('qmailanalog#do_update')->name('qmailanalog2');
|
|
|
|
$if_admin->get('/quota')->to('quota#main')->name('quota');
|
|
$if_admin->get('/quotad')->to('quota#do_display')->name('quotalist');
|
|
$if_admin->post('/quotad')->to('quota#do_update')->name('quotaupd');
|
|
$if_admin->post('/quota2')->to('quota#do_update')->name('quotaval');
|
|
|
|
$if_admin->get('/reboot')->to('reboot#main')->name('reboot');
|
|
$if_admin->post('/reboot')->to('reboot#do_action')->name('rebootact');
|
|
|
|
$if_admin->get('/remoteaccess')->to('remoteaccess#main')->name('remoteaccess');
|
|
$if_admin->post('/remoteaccess')->to('remoteaccess#do_action')->name('remoteaccessact');
|
|
|
|
$if_admin->get('/support')->to('support#main')->name('support');
|
|
|
|
$if_admin->get('/useraccounts')->to('useraccounts#main')->name('useraccounts');
|
|
$if_admin->post('/useraccounts')->to('useraccounts#do_display')->name('useraccountadd');
|
|
$if_admin->get('/useraccountsd')->to('useraccounts#do_display')->name('useraccountdis');
|
|
$if_admin->post('/useraccountsd')->to('useraccounts#do_update')->name('useraccountupd');
|
|
$if_admin->post('/useraccountso')->to('useraccounts#do_display')->name('useraccountvpn');
|
|
|
|
$if_admin->get('/viewlogfiles')->to('viewlogfiles#main')->name('viewlogfiles');
|
|
$if_admin->post('/viewlogfiles')->to('viewlogfiles#do_action')->name('viewlogfiles2');
|
|
$if_admin->post('/viewlogfilesr')->to('viewlogfiles#do_action')->name('viewlogfilesr');
|
|
|
|
$if_admin->get('/yum')->to('yum#main')->name('yum');
|
|
$if_admin->post('/yum')->to('yum#do_display')->name('yumd1');
|
|
$if_admin->get('/yumd')->to('yum#do_display')->name('yumd');
|
|
$if_admin->post('/yumd')->to('yum#do_update')->name('yumu');
|
|
|
|
$if_admin->get('/welcome')->to('welcome#main')->name('welcome');
|
|
|
|
$if_admin->get('/workgroup')->to('workgroup#main')->name('workgroup');
|
|
$if_admin->post('/workgroup')->to('workgroup#do_update')->name('workgroup2');
|
|
|
|
# additional routes (for contribs) got from 'routes' db
|
|
#my @routes = @{SrvMngr::get_routes_list()};
|
|
|
|
foreach (@{SrvMngr::get_routes_list()}) {
|
|
|
|
if ( defined $_->{method} and defined $_->{url} and defined $_->{ctlact} and defined $_->{name} ) {
|
|
my $menu = defined $_->{menu} ? $_->{menu} : 'A';
|
|
if ( $menu eq 'N' ) {
|
|
$r->get($_->{url})->to($_->{ctlact})->name($_->{name})
|
|
if ( $_->{method} eq 'get');
|
|
$r->post($_->{url})->to($_->{ctlact})->name($_->{name})
|
|
if ( $_->{method} eq 'post');
|
|
} elsif ( $menu eq 'U' ) {
|
|
$if_logged_in->get($_->{url})->to($_->{ctlact})->name($_->{name})
|
|
if ( $_->{method} eq 'get');
|
|
$if_logged_in->post($_->{url})->to($_->{ctlact})->name($_->{name})
|
|
if ( $_->{method} eq 'post');
|
|
} else {
|
|
$if_admin->get($_->{url})->to($_->{ctlact})->name($_->{name})
|
|
if ( $_->{method} eq 'get');
|
|
$if_admin->post($_->{url})->to($_->{ctlact})->name($_->{name})
|
|
if ( $_->{method} eq 'post');
|
|
}
|
|
}
|
|
}
|
|
|
|
$if_admin->get('/config/:key' => {key => qr/[a-z0-9]{2,32}/})->to('request#getconfig')->name('getconfig');
|
|
$if_admin->get('/account/:key' => {key => qr/[a-z0-9]{2,32}/})->to('request#getaccount')->name('getaccount');
|
|
$if_admin->get('/:module' => {module => qr/[a-z0-9]{2,32}/})->to('modules#modsearch')->name('module_search');
|
|
$if_admin->any('/*whatever' => {whatever => ''})->to('modules#whatever')->name('whatever');
|
|
|
|
}
|
|
|
|
|
|
sub setup_hooks {
|
|
my ($c) = @_;
|
|
|
|
$c->hook( before_routes => sub {
|
|
my $c = shift;
|
|
if ( not defined $c->session->{lang} ) {
|
|
SrvMngr::init_session ( $c );
|
|
}
|
|
$c->lang_space();
|
|
});
|
|
|
|
if ( my $path = $ENV{MOJO_REVERSE_PROXY} ) {
|
|
my @path_parts = grep /\S/, split m{/}, $path;
|
|
$c->hook( before_dispatch => sub {
|
|
my ( $c ) = @_;
|
|
my $url = $c->req->url;
|
|
my $base = $url->base;
|
|
push @{ $base->path }, @path_parts;
|
|
$base->path->trailing_slash(1);
|
|
$url->path->leading_slash(0);
|
|
});
|
|
}
|
|
|
|
}
|
|
|
|
|
|
sub init_session {
|
|
|
|
my $c = shift;
|
|
$c->app->log->info("Init app session.");
|
|
|
|
my %datas = ();
|
|
%datas = %{SrvMngr::Model::Main->init_data()};
|
|
|
|
$c->session->{lang} = $datas{'lang'};
|
|
$c->session->{copyRight} = $c->l($datas{'copyRight'});
|
|
$c->session->{releaseVersion} = $datas{'releaseVersion'};
|
|
$c->session->{PwdSet} = $datas{'PwdSet'};
|
|
$c->session->{SystemName} = $datas{'SystemName'};
|
|
$c->session->{DomainName} = $datas{'DomainName'};
|
|
$c->session->{Access} = $datas{'Access'};
|
|
if ( not defined $c->session->{CurrentTheme} ) {
|
|
$c->session->{CurrentTheme} = $c->config->{theme};
|
|
}
|
|
}
|
|
|
|
|
|
sub get_mod_url{
|
|
|
|
my $c = shift;
|
|
my $module = shift;
|
|
|
|
# test if module (panel) exists
|
|
my $module_file = $c->config->{modules_dir} . '/' . ucfirst($module) . '.pm';
|
|
if ( -e $module_file){
|
|
return "/$module";
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
=head2 theme_list()
|
|
|
|
Returns a hash of themes for the header theme field's drop down list.
|
|
|
|
=cut
|
|
|
|
|
|
sub theme_list {
|
|
|
|
my $c = shift;
|
|
|
|
my @files = ();
|
|
my @themes = ();
|
|
my $theme_ignore = "(\.\.?)";
|
|
|
|
# my $themedir = '/usr/share/smanager/themes/';
|
|
my $themedir = $c->app->home->rel_file('themes/');
|
|
|
|
if (opendir (DIR, $themedir)) {
|
|
@files = grep (!/^${theme_ignore}$/, readdir(DIR));
|
|
closedir (DIR);
|
|
} else {
|
|
warn "Can't open directory $themedir\n";
|
|
}
|
|
|
|
foreach my $theme (@files) {
|
|
if (-d "$themedir/$theme") {
|
|
push @themes, $theme;
|
|
}
|
|
}
|
|
|
|
return \@themes;
|
|
}
|
|
|
|
|
|
#------------------------------------------------------------
|
|
# subroutine to feed navigation bar
|
|
#------------------------------------------------------------
|
|
|
|
sub getNavigation {
|
|
|
|
use esmith::NavigationDB;
|
|
|
|
my $c = shift;
|
|
my $lang = shift || 'en-us';
|
|
my $menu = shift || 'N';
|
|
|
|
# my $lang = $c->session->{lang} || 'en-us';
|
|
|
|
# Use this variable throughout to keep track of files
|
|
# list of just the files
|
|
|
|
my @files = ();
|
|
my %files_hash = ();
|
|
|
|
#-----------------------------------------------------
|
|
# Determine the directory where the functions are kept
|
|
#-----------------------------------------------------
|
|
my $navigation_ctlr_ignore =
|
|
"(\.\.?|Swttheme\.pm|Login\.pm|Request\.pm|Modules\.pm|Legacypanel\.pm(-.*)?)";
|
|
# "(\.\.?|Initial\.pm|Manual\.pm|Swttheme\.pm|Request\.pm|Modules\.pm(-.*)?)";
|
|
my $navigation_cgi_ignore =
|
|
"(\.\.?|navigation|noframes|online-manual|(internal|pleasewait)(-.*)?)";
|
|
|
|
# my $ctrldir = $c->app->home->rel_file('lib/SrvMngr/Controller');
|
|
my $ctrldir = '/usr/share/smanager/lib/SrvMngr/Controller';
|
|
my $cgidir = '/etc/e-smith/web/panels/manager/cgi-bin/';
|
|
|
|
if (opendir (DIR, $ctrldir)) {
|
|
@files = grep (!/^${navigation_ctlr_ignore}$/,
|
|
readdir (DIR));
|
|
closedir (DIR);
|
|
} else {
|
|
warn "Can't open directory $ctrldir\n";
|
|
}
|
|
|
|
foreach my $file (@files) {
|
|
next if (-d "$ctrldir/$file");
|
|
next if ( $file !~ m/^[A-Z].*\.pm$/ );
|
|
|
|
my $file2 = lc($file);
|
|
$file2 =~ s/\.pm$//;
|
|
$files_hash{$file2} = 'ctrl';
|
|
}
|
|
|
|
# Is there some old panels not managed in new way ?
|
|
@files = ();
|
|
if (opendir (DIR, $cgidir)) {
|
|
@files = grep (!/^${navigation_cgi_ignore}$/,
|
|
readdir (DIR));
|
|
closedir (DIR);
|
|
}
|
|
|
|
foreach my $file (@files) {
|
|
next if (-d "$cgidir/$file");
|
|
$files_hash{$file} = 'cgim' if ( ! exists $files_hash{$file} );
|
|
}
|
|
|
|
#--------------------------------------------------
|
|
# For each script, extract the description and category
|
|
# information. Build up an associative array mapping headings
|
|
# to heading structures. Each heading structure contains the
|
|
# total weight for the heading, the number of times the heading
|
|
# has been encountered, and another associative array mapping
|
|
# descriptions to description structures. Each description
|
|
# structure contains the filename of the particular cgi script
|
|
# and a weight.
|
|
#--------------------------------------------------
|
|
my %nav = ();
|
|
|
|
use constant NAVIGATIONDIR => '/home/e-smith/db/navigation2';
|
|
# use constant WEBFUNCTIONS => '/etc/e-smith/web/functions';
|
|
|
|
my $navinfo = NAVIGATIONDIR . "/navigation.$lang";
|
|
|
|
my $navdb = esmith::NavigationDB->open_ro( $navinfo ) or
|
|
die "Couldn't open $navinfo\n";
|
|
|
|
# Check the navdb for anything with a UrlPath, which means that it doesn't
|
|
# have a cgi file to be picked up by the above code. Ideally, only pages
|
|
# that exist should be in the db, but that's not the case. Anything
|
|
# without a cgi file will have to remove themselves on uninstall from the
|
|
# navigation dbs.
|
|
foreach my $rec ($navdb->get_all)
|
|
{
|
|
if ($rec->prop('UrlPath'))
|
|
{
|
|
$files_hash{$rec->{key}} = $cgidir;
|
|
}
|
|
}
|
|
|
|
foreach my $file (keys %files_hash)
|
|
{
|
|
#my $heading = 'Unknown';
|
|
my $heading = 'Legacy';
|
|
|
|
my $description = $file;
|
|
my $headingWeight = 99999;
|
|
my $descriptionWeight = 99999;
|
|
my $urlpath = '';
|
|
my $menucat = 'A'; # admin menu (default)
|
|
|
|
my $rec = $navdb->get($file);
|
|
|
|
if (defined $rec)
|
|
{
|
|
$heading = $rec->prop('Heading');
|
|
$description = $rec->prop('Description');
|
|
$headingWeight = $rec->prop('HeadingWeight') || 99999; #Stop noise in logs if file in dir does not have nav header.
|
|
$descriptionWeight = $rec->prop('DescriptionWeight');
|
|
$urlpath = $rec->prop('UrlPath') || '';
|
|
$menucat = $rec->prop('MenuCat') || 'A'; # admin menu (default)
|
|
}
|
|
next if $menu ne $menucat;
|
|
|
|
#--------------------------------------------------
|
|
# add heading, description and weight information to data structure
|
|
#--------------------------------------------------
|
|
|
|
unless (exists $nav {$heading})
|
|
{
|
|
$nav {$heading} = { COUNT => 0, WEIGHT => 0, DESCRIPTIONS => [] };
|
|
}
|
|
|
|
$nav {$heading} {'COUNT'} ++;
|
|
$nav {$heading} {'WEIGHT'} += $headingWeight;
|
|
|
|
# Check for manager panel, and assign the appropriate
|
|
# cgi-bin prefix for the links.
|
|
# Grab the last 2 directories by splitting for '/'s and
|
|
# then concatenating the last 2
|
|
# probably a better way, but I don't know it.
|
|
|
|
my $path;
|
|
if ( $files_hash{$file} eq 'ctrl') {
|
|
$path = "2";
|
|
} elsif ( $files_hash{$file} eq 'cgim') {
|
|
$path = "/cgi-bin";
|
|
} else {
|
|
my @filename = split /\//, $files_hash{$file};
|
|
$path = "/$filename[scalar @filename - 2]/$filename[scalar @filename - 1]";
|
|
};
|
|
|
|
push @{ $nav {$heading} {'DESCRIPTIONS'} },
|
|
{ DESCRIPTION => $description,
|
|
WEIGHT => $descriptionWeight,
|
|
FILENAME => $urlpath ? $urlpath : "$path/$file",
|
|
CGIPATH => $path,
|
|
MENUCAT => $menucat
|
|
};
|
|
}
|
|
|
|
return \%nav;
|
|
|
|
}
|
|
|
|
|
|
sub _lang_space {
|
|
|
|
my $c = shift;
|
|
|
|
my $panel = $c->tx->req->url;
|
|
if ( $panel =~ m/\.css$|\.js$|\.jpg$|\.gif$|\.png$/ ) {
|
|
#warn "panel not treated $panel";
|
|
return
|
|
}
|
|
|
|
my $lang = ( $c->tx->req->headers->accept_language || ['en_US'] );
|
|
$lang = (split(/,/, $lang))[0];
|
|
# my $lang = (split(/,/, $c->tx->req->headers->accept_language))[0];
|
|
## convert xx_XX lang format to xx-xx + delete .UTFxx + lowercase
|
|
# $lang =~ s/_(.*)\..*$/-${1}/; # just keep 'en-us'
|
|
##$lang = lc( substr( $lang,0,2 ) ); # just keep 'en'
|
|
|
|
$panel = '/initial' if ($panel eq '/' or $panel eq '');
|
|
|
|
(my $module = $panel) =~ s|\?.*$||;
|
|
$module =~ s|^/||;
|
|
$module = ucfirst($module);
|
|
|
|
my $moduleLong = "SrvMngr::I18N::Modules::$module";
|
|
(my $dir = $moduleLong) =~ s|::|/|g;
|
|
my $I18Ndir = $c->app->home->rel_file('lib/') . '/' . $dir;
|
|
|
|
##$c->app->log->debug("$panel $module $moduleLong $I18Ndir");
|
|
if ( ! -d $I18Ndir ) {
|
|
( $moduleLong = $moduleLong) =~ s/.$//;
|
|
( $I18Ndir = $I18Ndir) =~ s/.$//;
|
|
}
|
|
if ( -d $I18Ndir ) {
|
|
## $c->app->log->debug("hook_b_r->panel route. lang: $lang namespace: $moduleLong ldir; $I18Ndir");
|
|
warn "NS already loaded: $moduleLong \n" if ( $c->i18ns() eq $moduleLong ); # i18ns changed
|
|
$c->i18ns( $moduleLong, $lang );
|
|
} else {
|
|
warn "Locale lexicon missing for $module \n";
|
|
}
|
|
};
|
|
|
|
|
|
sub get_routes_list {
|
|
|
|
my $c = shift;
|
|
|
|
my $rtdb = esmith::ConfigDB->open_ro('routes') || die 'Cannot open Routes db';
|
|
my @routes = $rtdb->get_all();
|
|
my @rt;
|
|
|
|
for (@routes) {
|
|
my ( $contrib, $name ) = split ( /\+/, $_->key);
|
|
push @rt,
|
|
{ 'method' => $_->prop('Method'), 'url' => $_->prop('Url'),
|
|
'ctlact' => $_->prop('Ctlact'), 'menu' => $_->prop('Menu'),
|
|
'name' => $name, 'contrib' => $contrib,
|
|
};
|
|
}
|
|
return \@rt;
|
|
|
|
}
|
|
|
|
|
|
sub ip_number {
|
|
|
|
# from CGI::FormMagick::Validator qw( ip_number );
|
|
|
|
my ($c, $data) = @_;
|
|
|
|
return undef unless defined $data;
|
|
|
|
return $c->l('FM_IP_NUMBER1') . " (" . $data . ")" unless $data =~ /^[\d.]+$/;
|
|
|
|
my @octets = split /\./, $data;
|
|
my $dots = ($data =~ tr/.//);
|
|
|
|
return $c->l('FM_IP_NUMBER2') unless (scalar @octets == 4 and $dots == 3);
|
|
|
|
foreach my $octet (@octets) {
|
|
return $c->l("FM_IP_NUMBER3", $octet) if $octet > 255;
|
|
}
|
|
|
|
return 'OK';
|
|
}
|
|
|
|
|
|
sub is_normal_password {
|
|
|
|
# from CGI::FormMagick::Validator qw( password );
|
|
|
|
my ($c, $data) = @_;
|
|
$_ = $data;
|
|
if (not defined $_) {
|
|
return $c->l("FM_PASSWORD1");
|
|
} elsif (/\d/ and /[A-Z]/ and /[a-z]/ and /\W|_/ and length($_) > 6) {
|
|
return "OK";
|
|
} else {
|
|
return $c->l("FM_PASSWORD2");
|
|
}
|
|
}
|
|
|
|
|
|
sub email_simple {
|
|
my ($c, $data) = @_;
|
|
|
|
use Mail::RFC822::Address;
|
|
|
|
if (not defined $data ) {
|
|
return $c->l("FM_EMAIL_SIMPLE1");
|
|
} elsif (Mail::RFC822::Address::valid($data)) {
|
|
return "OK";
|
|
} else {
|
|
return $c->l("FM_EMAIL_SIMPLE2");
|
|
}
|
|
}
|
|
|
|
|
|
sub mac_address_or_blank {
|
|
my ($c, $data) = @_;
|
|
return "OK" unless $data;
|
|
return mac_address($c, $data);
|
|
}
|
|
|
|
|
|
sub mac_address {
|
|
|
|
# from CGI::FormMagick::Validator::Network
|
|
|
|
my ($c, $data) = @_;
|
|
|
|
$_ = lc $data; # easier to match on $_
|
|
if (not defined $_) {
|
|
return $c->l('FM_MAC_ADDRESS1');
|
|
} elsif (/^([0-9a-f][0-9a-f](:[0-9a-f][0-9a-f]){5})$/) {
|
|
return "OK";
|
|
} else {
|
|
return $c->l('FM_MAC_ADDRESS2');
|
|
}
|
|
}
|
|
|
|
|
|
sub ip_number_or_blank {
|
|
|
|
# XXX - FIXME - we should push this down into CGI::FormMagick
|
|
|
|
my $c = shift;
|
|
my $ip = shift;
|
|
|
|
if (!defined($ip) || $ip eq "")
|
|
{
|
|
return 'OK';
|
|
}
|
|
|
|
return ip_number( $c, $ip );
|
|
}
|
|
|
|
|
|
sub subnet_mask {
|
|
|
|
my ( $data ) = @_;
|
|
|
|
# we test for a valid mask or bit mask
|
|
my $tip="192.168.1.50";
|
|
my $block = new Net::Netmask("$tip/$data") or return "INV1 $data";
|
|
|
|
if ($block->mask() eq "$data" || $block->bits() eq "$data") {
|
|
return "OK";
|
|
}
|
|
return "INV2 $data";
|
|
}
|
|
|
|
|
|
sub get_reg_mask {
|
|
|
|
my ( $address, $mask ) = @_;
|
|
|
|
# we transform bit mask to regular mask
|
|
my $block = new Net::Netmask("$address/$mask");
|
|
|
|
return $block->mask();
|
|
}
|
|
|
|
|
|
1;
|