#!/usr/bin/env perl # # ChivaNet Moderator Console # Copyright (C) 2025 Coherent Logic Development LLC # # $Id: modcon,v 1.2 2025/01/31 13:38:51 snw Exp $ # # Author: Serena Willis # # Licensed AGPL-3.0 # # $Log: modcon,v $ # Revision 1.2 2025/01/31 13:38:51 snw # Initial basic functions working # # Revision 1.1.1.1 2025/01/30 19:16:06 snw # Initial commit # # use REST::Client; use JSON; use Getopt::Long; use Data::Dumper; use Term::ReadKey; my $rasurl = ''; my $apikey = ''; my $online = 0; my $modcon_version = '0.0.1'; my $cnclient = ''; my $rasclient = ''; my $wchar = ''; my $hchar = ''; my $wpixels = ''; my $hpixels = ''; my $account = ''; sub list_sso_users { $cnclient->GET("/chivanet/users"); my $ct = 0; my $json = $cnclient->responseContent(); my $hashref = decode_json($json); if($hashref->{ok} == 1) { my $arrayref = $hashref->{users}; my @users = sort(@{$arrayref}); foreach my $user (@users) { print "$user\n"; $ct = $ct + 1; if($ct > $hchar - 2) { print "ENTER to continue, Q to quit..."; my $resp = ; chomp($resp); if($resp eq "Q") { return; } elsif($resp eq "q") { return; } $ct = 0; } } } else { print "RPC error\n"; } } sub list_ras_users { } sub select_sso_user { my($id) = @_; $cnclient->GET("/chivanet/validate_user?id=$id"); my $json = $cnclient->responseContent(); my $hashref = decode_json($json); #print Dumper($hashref); if($hashref->{exists} == 1) { $cnclient->GET("/chivanet/user?id=$id"); my $json = $cnclient->responseContent(); $account = decode_json($json); return $id; } else { print ">>> invalid SSO user $id [$hashref->{error}]\n"; return "---"; } } sub select_ras_user { my($id) = @_; $cnclient->GET("/chivanet/validate_sn?id=$id"); my $json = $cnclient->responseContent(); my $hashref = decode_json($json); if($hashref->{exists} == 1) { return $id; } else { print ">>> invalid RAS screen name $id\n"; return "---"; } } sub trace_ras_sn { my($user) = @_; $cnclient->GET("/chivanet/trace_sn?id=$user"); my $json = $cnclient->responseContent(); my $hashref = decode_json($json); my $record = $hashref->{account}; my $result = $record->{id}; print "RAS screen name $user belongs to SSO account $result; switching to SSO mode\n"; return $result; } sub list_ras_sessions { $cnclient->GET("/chivanet/ras_sessions"); my $json = $cnclient->responseContent(); my $hashref = decode_json($json); my $sessions = $hashref->{sessions}; my $arrayref = $sessions->{sessions}; my $ct = 0; foreach my $session (@{$arrayref}) { print "$session->{screen_name}\n"; $ct = $ct + 1; if($ct > $hchar - 2) { print "ENTER to continue, Q to quit..."; my $resp = ; chomp($resp); if($resp eq "Q") { return; } elsif($resp eq "q") { return; } $ct = 0; } } print "$sessions->{count} current sessions\n"; } sub list_ras_screennames { my($id) = @_; $cnclient->GET("/chivanet/ras_screen_names?id=$id"); my $json = $cnclient->responseContent(); my $hashref = decode_json($json); my $arrayref = $hashref->{screen_names}; my $ct = 0; foreach my $sn (@{$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) { print "ENTER to continue, Q to quit..."; my $resp = ; chomp($resp); if($resp eq "Q") { return; } elsif($resp eq "q") { return; } $ct = 0; } } } sub print_sso_user { my $act = $account->{account}; print "\n"; print "Username : $act->{id}\n"; print "Real Name : $act->{last_name}, $act->{first_name}\n"; print "Display Name : $act->{display_name}\n"; print "Pronouns : $act->{pronouns}\n"; print "Profile Image : https://chivanet.org$act->{profile_photo}\n"; print "E-Mail Address : $act->{email}\n"; print "Permission Level : $act->{perm_level}\n"; print "Created : $act->{create_ts}\n"; print "Banned : $act->{mod_banned}\n\n"; } sub print_ras_user { my($id) = @_; $cnclient->GET("/chivanet/sn_status?id=$id"); my $json = $cnclient->responseContent(); my $hashref = decode_json($json); my $status = $hashref->{status}; my $online = "offline"; if($status->{online} == 1) { $online = "online"; } print "\n"; if($online eq "online") { my $sess = $status->{session}; my $service = 'AIM'; if($sess->{is_icq} == 1) { $service = 'ICQ'; } if($sess->{idle_seconds} > 0) { $online = "idle"; } print "Screen Name : $id [$online]\n"; print "Service : $service\n"; if($online eq "online") { print "Time Online (secs): $sess->{online_seconds}\n"; } else { print "Time Idle (secs) : $sess->{idle_seconds}\n"; } print "Away Message : $sess->{away_message}\n\n"; } else { print "Screen Name : $id [$online]\n\n"; } # print Dumper($status); } sub send_im { my($user, $msgbody) = @_; print "sending message \"$msgbody\" to $user..."; my $msg = "[ChivaNet Support]: $msgbody"; $cnclient->GET("/chivanet/send_im?from=ChivaNet&to=$user&message=$msg"); my $json = $cnclient->responseContent(); my $hashref = decode_json($json); if($hashref->{status} == 1) { print "[OK]\n"; } else { print "[FAIL]\n"; } } sub prompt { my $rawcmd = ''; my $mode = '---'; my $user = '---'; while (1) { print "MODCON [$mode/$user]> "; my $line = ; chomp($line); $rawcmd = $line; my @cmd = split(' ', $rawcmd); if ($cmd[0] eq "quit") { return; } elsif ($cmd[0] eq "mode") { if($cmd[1] eq "sso") { $mode = "SSO"; $user = "---"; $account = ''; } elsif ($cmd[1] eq "ras") { $mode = "RAS"; $user = "---"; $account = ''; } else { print "?\n"; } } elsif ($cmd[0] eq "select") { 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 { print "?\n"; } } else { print "?\n"; } } elsif ($cmd[0] eq "im") { if($mode eq "RAS") { if($user ne "---") { my @msga = @cmd[1..$#cmd]; my $msgbody = join(' ', @msga); send_im($user, $msgbody); } else { print "?\n"; } } else { print "?\n"; } } elsif ($cmd[0] eq "trace") { if($mode eq "RAS") { if($user ne "---") { my $id = trace_ras_sn($user); $mode = "SSO"; $user = select_sso_user($id); print_sso_user; } else { print "?\n"; } } else { print "?\n"; } } elsif ($cmd[0] eq "field") { if($user ne "---") { my $act = $account->{account}; print "$user\-\>$cmd[1]: $act->{$cmd[1]}\n"; } else { print "?\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 { print "?\n"; } } elsif ($cmd[0] eq "list") { if($cmd[1] eq "users") { if($mode eq "SSO") { list_sso_users(); } elsif($mode eq "RAS") { list_ras_users(); } } elsif($cmd[1] eq "sessions") { if($mode eq "RAS") { list_ras_sessions(); } else { print "?\n"; } } elsif($cmd[1] eq "sn") { if($mode eq "SSO") { if($user ne "---") { list_ras_screennames $user; } else { print "?\n"; } } else { print "?\n"; } } else { print "?\n"; } } else { print "?\n" } } } sub main { GetOptions("rasurl=s" => \$rasurl, "apikey=s" => \$apikey) or die("error in command line arguments"); ($wchar, $hchar, $wpixels, $hpixels) = GetTerminalSize(); $cnclient = REST::Client->new({ host => 'https://chivanet.org/rest/api', timeout => 10}); $cnclient->addHeader('Authorization', "Apikey $apikey"); $rasclient = REST::Client->new({ host => $rasurl, timeout => 10}); print "ChivaNet MODCON $modcon_version\n"; print " Copyright (C) 2025 Coherent Logic Development LLC\n\n"; prompt(); print "Goodbye.\n" } main();