version 1.2, 2025/01/31 13:38:51
|
version 1.4, 2025/01/31 19:41:00
|
Line 11
|
Line 11
|
# Licensed AGPL-3.0 |
# Licensed AGPL-3.0 |
# |
# |
# $Log$ |
# $Log$ |
|
# Revision 1.4 2025/01/31 19:41:00 snw |
|
# Move to a UNIX UI paradigm |
|
# |
|
# Revision 1.3 2025/01/31 15:39:06 snw |
|
# Minor fixes |
|
# |
# Revision 1.2 2025/01/31 13:38:51 snw |
# Revision 1.2 2025/01/31 13:38:51 snw |
# Initial basic functions working |
# Initial basic functions working |
# |
# |
Line 21
|
Line 27
|
|
|
use REST::Client; |
use REST::Client; |
use JSON; |
use JSON; |
use Getopt::Long; |
|
use Data::Dumper; |
use Data::Dumper; |
use Term::ReadKey; |
use Term::ReadKey; |
|
use Getopt::Long; |
|
|
my $rasurl = ''; |
my $sso_account = ''; |
my $apikey = ''; |
my $apikey = ''; |
my $online = 0; |
my $online = 0; |
my $modcon_version = '0.0.1'; |
my $modcon_version = '0.0.1'; |
my $cnclient = ''; |
my $cnclient = ''; |
my $rasclient = ''; |
|
|
|
my $wchar = ''; |
my $wchar = ''; |
my $hchar = ''; |
my $hchar = ''; |
my $wpixels = ''; |
my $wpixels = ''; |
my $hpixels = ''; |
my $hpixels = ''; |
|
|
my $account = ''; |
my $account = ''; |
|
my $mode = '---'; |
|
my $user = '---'; |
|
$site = ''; |
|
|
|
sub list_directories { |
|
return ('sso', 'ras'); |
|
} |
|
|
sub list_sso_users { |
sub list_sso_users { |
$cnclient->GET("/chivanet/users"); |
$cnclient->GET("/chivanet/users"); |
my $ct = 0; |
|
|
|
my $json = $cnclient->responseContent(); |
my $json = $cnclient->responseContent(); |
my $hashref = decode_json($json); |
my $hashref = decode_json($json); |
|
|
if($hashref->{ok} == 1) { |
if($hashref->{ok} == 1) { |
my $arrayref = $hashref->{users}; |
my $arrayref = $hashref->{users}; |
my @users = sort(@{$arrayref}); |
my @users = @{$arrayref}; |
|
|
foreach my $user (@users) { |
return @users; |
print "$user\n"; |
|
$ct = $ct + 1; |
|
|
|
if($ct > $hchar - 2) { |
|
print "ENTER to continue, Q to quit..."; |
|
my $resp = <STDIN>; |
|
chomp($resp); |
|
if($resp eq "Q") { |
|
return; |
|
} |
|
elsif($resp eq "q") { |
|
return; |
|
} |
|
$ct = 0; |
|
} |
|
} |
|
} |
} |
else { |
else { |
print "RPC error\n"; |
print "RPC error\n"; |
|
return (); |
} |
} |
} |
} |
|
|
sub list_ras_users { |
|
|
|
} |
|
|
|
sub select_sso_user { |
sub select_sso_user { |
my($id) = @_; |
my($id) = @_; |
Line 83 sub select_sso_user {
|
Line 73 sub select_sso_user {
|
$cnclient->GET("/chivanet/validate_user?id=$id"); |
$cnclient->GET("/chivanet/validate_user?id=$id"); |
my $json = $cnclient->responseContent(); |
my $json = $cnclient->responseContent(); |
my $hashref = decode_json($json); |
my $hashref = decode_json($json); |
|
|
#print Dumper($hashref); |
|
|
|
if($hashref->{exists} == 1) { |
if($hashref->{exists} == 1) { |
|
|
$cnclient->GET("/chivanet/user?id=$id"); |
$cnclient->GET("/chivanet/user?id=$id"); |
my $json = $cnclient->responseContent(); |
my $json = $cnclient->responseContent(); |
$account = decode_json($json); |
$account = decode_json($json); |
|
|
return $id; |
return $id; |
} |
} |
else { |
else { |
print ">>> invalid SSO user $id [$hashref->{error}]\n"; |
|
return "---"; |
return "---"; |
} |
} |
|
|
} |
} |
|
|
sub select_ras_user { |
sub select_ras_user { |
Line 112 sub select_ras_user {
|
Line 98 sub select_ras_user {
|
return $id; |
return $id; |
} |
} |
else { |
else { |
print ">>> invalid RAS screen name $id\n"; |
|
return "---"; |
return "---"; |
} |
} |
} |
} |
Line 127 sub trace_ras_sn {
|
Line 112 sub trace_ras_sn {
|
my $result = $record->{id}; |
my $result = $record->{id}; |
|
|
print "RAS screen name $user belongs to SSO account $result; switching to SSO mode\n"; |
print "RAS screen name $user belongs to SSO account $result; switching to SSO mode\n"; |
return $result; |
return $result; |
|
|
} |
} |
|
|
sub list_ras_sessions { |
sub list_ras_sessions { |
Line 158 sub list_ras_sessions {
|
Line 142 sub list_ras_sessions {
|
} |
} |
} |
} |
|
|
print "$sessions->{count} current sessions\n"; |
print "$sessions->{count} current sessions\n"; |
|
|
} |
} |
|
|
sub list_ras_screennames { |
sub list_ras_screennames { |
my($id) = @_; |
my($id) = @_; |
|
|
$cnclient->GET("/chivanet/ras_screen_names?id=$id"); |
$cnclient->GET("/chivanet/ras_screen_names?id=$id"); |
|
|
my $json = $cnclient->responseContent(); |
my $json = $cnclient->responseContent(); |
my $hashref = decode_json($json); |
my $hashref = decode_json($json); |
my $arrayref = $hashref->{screen_names}; |
my $arrayref = $hashref->{screen_names}; |
my $ct = 0; |
|
|
|
foreach my $sn (@{$arrayref}) { |
return @{$arrayref}; |
my $name = "$sn->{screen_name}\n"; |
} |
chomp($name); |
|
|
|
my $bot = ''; |
|
my $public = ''; |
|
|
|
if($sn->{bot_sn} eq 1) { |
|
$bot = "bot"; |
|
} |
|
else { |
|
$bot = "human"; |
|
} |
|
|
|
if($sn->{public_sn} eq 1) { |
|
$public = "public"; |
|
} |
|
else { |
|
$public = "unlisted"; |
|
} |
|
|
|
print "$name: $public $bot; created $sn->{create_ts}\n"; |
|
|
|
$ct = $ct + 1; |
|
|
|
if($ct > $hchar - 2) { |
sub list_ras_users { |
print "ENTER to continue, Q to quit..."; |
|
my $resp = <STDIN>; |
|
chomp($resp); |
|
if($resp eq "Q") { |
|
return; |
|
} |
|
elsif($resp eq "q") { |
|
return; |
|
} |
|
$ct = 0; |
|
} |
|
} |
|
|
|
|
return (); |
|
|
} |
} |
|
|
sub print_sso_user { |
sub print_sso_user { |
Line 296 sub send_im {
|
Line 245 sub send_im {
|
sub prompt { |
sub prompt { |
|
|
my $rawcmd = ''; |
my $rawcmd = ''; |
my $mode = '---'; |
my $pmode = $mode; |
my $user = '---'; |
my @path = (); |
|
|
while (1) { |
while (1) { |
print "MODCON [$mode/$user]> "; |
$pmode = lc $mode; |
|
my $prompt = ''; |
|
if($pmode ne "---") { |
|
if($user eq '---') { |
|
$prompt = "$sso_account\@$site:[/$pmode]\$ "; |
|
} |
|
else { |
|
$prompt = "$sso_account\@$site:[/$pmode/$user]\$ "; |
|
} |
|
} |
|
else { |
|
$prompt = "$sso_account\@$site:[/]\$ "; |
|
} |
|
print $prompt; |
my $line = <STDIN>; |
my $line = <STDIN>; |
chomp($line); |
chomp($line); |
$rawcmd = $line; |
$rawcmd = $line; |
|
|
my @cmd = split(' ', $rawcmd); |
my @cmd = split(' ', $rawcmd); |
|
|
if ($cmd[0] eq "quit") { |
if ($cmd[0] eq "exit" || $cmd[0] eq "logout" || $cmd[0] eq "quit" || $cmd[0] eq "bye") { |
return; |
return; |
} |
} |
elsif ($cmd[0] eq "mode") { |
elsif ($cmd[0] eq "pwd") { |
if($cmd[1] eq "sso") { |
my $pstr = join('/', @path); |
$mode = "SSO"; |
print "/$pstr\n"; |
$user = "---"; |
} |
$account = ''; |
elsif ($cmd[0] eq "cd") { |
} |
my $abspath = false; |
elsif ($cmd[1] eq "ras") { |
|
$mode = "RAS"; |
if($cmd[1] eq "..") { |
$user = "---"; |
if(@path) { |
$account = ''; |
if($#path == 1) { |
} |
$user = "---"; |
else { |
@path = ($pmode); |
print "?\n"; |
} |
} |
elsif($#path == 0) { |
} |
$mode = "---"; |
elsif ($cmd[0] eq "select") { |
@path = (); |
if($cmd[1] eq "user") { |
} |
if($mode eq "SSO") { |
|
$user = select_sso_user($cmd[2]); |
|
chomp($user); |
|
print_sso_user; |
|
} |
|
elsif($mode eq "RAS") { |
|
$user = select_ras_user($cmd[2]); |
|
chomp($user); |
|
print_ras_user $user; |
|
} |
} |
else { |
else { |
print "?\n"; |
print "already in root directory\n"; |
} |
} |
} |
|
else { |
|
print "?\n"; |
|
} |
} |
|
else { |
|
my @oldpath = @path; |
|
@path = split('/', $cmd[1]); |
|
|
|
if(substr($cmd[1], 0, 1) eq '/') { |
|
$abspath = true; |
|
shift @path; |
|
} |
|
|
|
if($abspath eq true || !@oldpath) { |
|
if($#path == 0) { |
|
# mode, no user |
|
if($path[0] eq "sso") { |
|
$mode = "SSO"; |
|
$user = "---"; |
|
@path = ('sso'); |
|
} |
|
elsif($path[0] eq "ras") { |
|
$mode = "RAS"; |
|
$user = "---"; |
|
@path = ('ras'); |
|
} |
|
else { |
|
print "$path[0]: no such directory exists\n"; |
|
@path = @oldpath; |
|
} |
|
} |
|
elsif($#path == 1) { |
|
# mode and user |
|
if($path[0] eq "sso") { |
|
$user = select_sso_user($path[1]); |
|
if($user eq "---") { |
|
print "$path[1]: no such file exists in $pmode\n"; |
|
@path = @oldpath; |
|
} |
|
else { |
|
$mode = "SSO"; |
|
@path = ('sso', $user); |
|
} |
|
} |
|
elsif($path[0] eq "ras") { |
|
$user = select_ras_user($path[1]); |
|
if($user eq "---") { |
|
print "$path[1]: no such file exists in $pmode\n"; |
|
@path = @oldpath; |
|
} |
|
else { |
|
$mode = "RAS"; |
|
@path = ('ras', $user); |
|
} |
|
} |
|
else { |
|
print "$path[0]: no such directory exists\n"; |
|
@path = @oldpath; |
|
} |
|
} |
|
else { |
|
if($cmd[1] eq '/') { |
|
$mode = '---'; |
|
$user = '---'; |
|
@path = (); |
|
} |
|
else { |
|
print "cd: invalid path specification\n"; |
|
@path = @oldpath; |
|
} |
|
} |
|
} |
|
else { |
|
if($#oldpath == 1) { |
|
print "invalid path specification\n"; |
|
@path = @oldpath; |
|
} |
|
else { |
|
if($#path == 0) { |
|
if($pmode eq "sso") { |
|
$user = select_sso_user($path[0]); |
|
if($user eq "---") { |
|
print "$path[0]: no such file exists in $pmode\n"; |
|
@path = @oldpath; |
|
} |
|
else { |
|
$mode = "SSO"; |
|
@path = ('sso', $user); |
|
} |
|
} |
|
elsif($pmode eq "ras") { |
|
$user = select_ras_user($path[0]); |
|
if($user eq "---") { |
|
print "$path[0]: no such file exists in $pmode\n"; |
|
@path = @oldpath; |
|
} |
|
else { |
|
$mode = "SSO"; |
|
@path = ('sso', $user); |
|
} |
|
} |
|
else { |
|
print "$path[0]: no such directory exists\n"; |
|
@path = @oldpath; |
|
} |
|
} |
|
else { |
|
print "invalid path specification\n"; |
|
@path = @oldpath; |
|
} |
|
} |
|
} |
|
} # if .. |
|
|
} |
} |
elsif ($cmd[0] eq "im") { |
elsif ($cmd[0] eq "im") { |
if($mode eq "RAS") { |
if($mode eq "RAS") { |
Line 353 sub prompt {
|
Line 413 sub prompt {
|
send_im($user, $msgbody); |
send_im($user, $msgbody); |
} |
} |
else { |
else { |
print "?\n"; |
print "im: no user selected\n"; |
} |
} |
} |
} |
else { |
else { |
print "?\n"; |
print "im: invalid command outside of ras directory\n"; |
} |
} |
} |
} |
elsif ($cmd[0] eq "trace") { |
elsif ($cmd[0] eq "trace") { |
Line 369 sub prompt {
|
Line 429 sub prompt {
|
print_sso_user; |
print_sso_user; |
} |
} |
else { |
else { |
print "?\n"; |
print "trace: no user select\n"; |
} |
} |
} |
} |
else { |
else { |
print "?\n"; |
print "trace: invalid command outside of ras directory\n"; |
} |
} |
} |
} |
elsif ($cmd[0] eq "field") { |
elsif ($cmd[0] eq "field") { |
if($user ne "---") { |
if($mode eq "SSO") { |
my $act = $account->{account}; |
if($user ne "---") { |
print "$user\-\>$cmd[1]: $act->{$cmd[1]}\n"; |
my $act = $account->{account}; |
} |
print "$user\-\>$cmd[1]: $act->{$cmd[1]}\n"; |
else { |
} |
print "?\n"; |
else { |
} |
print "field: no user selected\n"; |
} |
|
elsif ($cmd[0] eq "describe") { |
|
if($user ne "---") { |
|
if($mode eq "SSO") { |
|
print_sso_user; |
|
} |
} |
elsif($mode eq "RAS") { |
|
print_ras_user($user); |
|
} |
|
} |
} |
else { |
else { |
print "?\n"; |
print "field: command invalid outside of ras directory\n"; |
} |
} |
} |
} |
elsif ($cmd[0] eq "list") { |
elsif ($cmd[0] eq "ls") { |
if($cmd[1] eq "users") { |
my @entries = (); |
if($mode eq "SSO") { |
|
list_sso_users(); |
if($mode eq "---") { |
} |
@entries = list_directories(); |
elsif($mode eq "RAS") { |
|
list_ras_users(); |
|
} |
|
} |
} |
elsif($cmd[1] eq "sessions") { |
else { |
if($mode eq "RAS") { |
if($user ne "---") { |
list_ras_sessions(); |
if($mode eq "SSO") { |
|
print_sso_user; |
|
} |
|
elsif($mode eq "RAS") { |
|
print_ras_user($user); |
|
} |
} |
} |
else { |
else { |
print "?\n"; |
if($mode eq "SSO") { |
} |
@entries = list_sso_users(); |
} |
|
elsif($cmd[1] eq "sn") { |
|
if($mode eq "SSO") { |
|
if($user ne "---") { |
|
list_ras_screennames $user; |
|
} |
} |
else { |
else { |
print "?\n"; |
@entries = list_ras_users(); |
} |
} |
} |
} |
else { |
|
print "?\n"; |
|
} |
|
} |
} |
else { |
|
print "?\n"; |
if(@entries) { |
|
my $col = 0; |
|
my $pstr = join('/', @path); |
|
my $pfin = "/$pstr"; |
|
my @sorted = sort(@entries); |
|
my $maxlen = 0; |
|
foreach my $entry (@sorted) { |
|
my $len = length($entry); |
|
if ($len > $maxlen) { |
|
$maxlen = $len; |
|
} |
|
} |
|
$maxlen = $maxlen + 2; |
|
my $ct = $#sorted + 1; |
|
foreach my $entry (@sorted) { |
|
if($col + $maxlen >= $wchar) { |
|
print "\n"; |
|
$col = 0; |
|
} |
|
else { |
|
printf("%-$maxlen\s", $entry); |
|
$col = $col + $maxlen; |
|
} |
|
} |
|
print "\n\t$ct items in $pfin\n"; |
} |
} |
|
|
} |
} |
else { |
else { |
print "?\n" |
print "$cmd[0]: command not found\n"; |
} |
} |
} |
} |
|
|
} |
} |
|
|
sub main { |
sub main { |
GetOptions("rasurl=s" => \$rasurl, |
($wchar, $hchar, $wpixels, $hpixels) = GetTerminalSize(); |
"apikey=s" => \$apikey) |
|
or die("error in command line arguments"); |
|
|
|
($wchar, $hchar, $wpixels, $hpixels) = GetTerminalSize(); |
GetOptions("site=s" => \$site) or die "error in command line arguments"; |
|
|
|
if($site eq "") { |
|
print "modcon: must supply -site command-line argument\n"; |
|
return; |
|
} |
|
|
$cnclient = REST::Client->new({ |
$cnclient = REST::Client->new({ |
host => 'https://chivanet.org/rest/api', |
host => "https://$site/rest/api", |
timeout => 10}); |
timeout => 10}); |
|
|
$cnclient->addHeader('Authorization', "Apikey $apikey"); |
|
|
|
$rasclient = REST::Client->new({ |
|
host => $rasurl, |
|
timeout => 10}); |
|
|
|
print "ChivaNet MODCON $modcon_version\n"; |
print "ChivaNet MODCON $modcon_version\n"; |
print " Copyright (C) 2025 Coherent Logic Development LLC\n\n"; |
print " Copyright (C) 2025 Coherent Logic Development LLC\n\n"; |
|
|
|
print "username: "; |
|
$sso_account = <STDIN>; |
|
chomp($sso_account); |
|
|
|
print "password: "; |
|
ReadMode('noecho'); |
|
my $password = <STDIN>; |
|
chomp($password); |
|
ReadMode('normal'); |
|
|
|
|
|
my $params = $cnclient->buildQuery([username => $sso_account, password => $password]); |
|
my $result = $cnclient->POST("/chivanet/modcon_auth", substr($params, 1), {'Content-type' => 'application/x-www-form-urlencoded'}); |
|
my $http_response = $result->{_res}; |
|
my $json = $http_response->{_content}; |
|
my $apiresult = decode_json($json); |
|
|
prompt(); |
if($apiresult->{ok} == 1) { |
|
$cnclient->addHeader('Authorization', "Apikey $apiresult->{token}"); |
|
|
|
select_sso_user $sso_account; |
|
my $act = $account->{account}; |
|
|
|
print "\n\nWelcome to MODCON, $act->{display_name}!\n\n"; |
|
|
|
prompt(); |
|
} |
|
else { |
|
print "\nerror: $apiresult->{error}\n"; |
|
return; |
|
} |
|
|
print "Goodbye.\n" |
print "Goodbye.\n" |
} |
} |
|
|