From b24b20ec895032e8a013683fcb24ac79cd08f444 Mon Sep 17 00:00:00 2001 From: Digimer Date: Fri, 20 Jul 2018 03:08:44 -0400 Subject: [PATCH] * Working on saving the new peer. Made progress on, but not yet finished, sanity checking the new peer form values. * Cleaned up some docs. Signed-off-by: Digimer --- Anvil/Tools.pm | 26 +++--- Anvil/Tools/Validate.pm | 16 ++-- cgi-bin/home | 158 +++++++++++++++++++++++++++++++- html/skins/alteeve/striker.html | 74 +++++++++++++-- share/words.xml | 3 + 5 files changed, 245 insertions(+), 32 deletions(-) diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index 55ae8dc8a..2677f6ca1 100755 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -150,6 +150,19 @@ sub new # Record the start time. $anvil->data->{ENV_VALUES}{START_TIME} = Time::HiRes::time; + # Set passed parameters if needed. + if (ref($parameter) eq "HASH") + { + ### TODO: Calls to allow the user to override defaults... + # Local parameters... + } + elsif ($parameter) + { + # Um... + print $THIS_FILE." ".__LINE__."; Anvil::Tools->new() invoked with an invalid parameter. Expected a hash reference, but got: [$parameter]\n"; + exit(1); + } + # Get a handle on the various submodules $anvil->Account->parent($anvil); $anvil->Alert->parent($anvil); @@ -207,20 +220,7 @@ sub new $anvil->Get->switches; # Read in the local Anvil! version. - - # Set passed parameters if needed. - if (ref($parameter) eq "HASH") - { - ### TODO: Calls to allow the user to override defaults... - # Local parameters... - } - elsif ($parameter) - { - # Um... - print $THIS_FILE." ".__LINE__."; Anvil::Tools->new() invoked with an invalid parameter. Expected a hash reference, but got: [$parameter]\n"; - exit(1); - } return ($self); } diff --git a/Anvil/Tools/Validate.pm b/Anvil/Tools/Validate.pm index 6f5c656d8..0330c10a5 100755 --- a/Anvil/Tools/Validate.pm +++ b/Anvil/Tools/Validate.pm @@ -88,7 +88,7 @@ sub parent This validates that a given HTML form field is valid. It takes an input ID and the type of data that is expected. If it is sane, C<< 1 >> is returned. If it fails to validate, C<< 0 >> is returned and C<< cgi::::alert >> is set to C<< 1 >>. -=head2 Parameters; +Parameters; =head3 empty_ok (optional) @@ -222,7 +222,7 @@ NOTE: An empty string is considered invalid. print "The string: [$string] is valid!\n"; } -=head2 Parameters; +Parameters; =head3 string (required) @@ -266,7 +266,7 @@ Checks if the passed-in string is a valid domain name. Returns 'C<< 1 >>' if OK, print "The domain name: [$name] is valid!\n"; } -=head2 Parameters; +Parameters; =head3 name (required) @@ -310,7 +310,7 @@ Checks if the passed-in string is an IPv4 address. Returns 'C<< 1 >>' if OK, 'C< print "The IP address: [$ip] is valid!\n"; } -=head2 Parameters; +Parameters; =head3 ip (required) @@ -367,7 +367,7 @@ sub is_ipv4 Checks if the passed-in string is a valid network MAC address. Returns 'C<< 1 >>' if OK, 'C<< 0 >>' if not. -=head2 Parameters; +Parameters; =head3 mac (required) @@ -408,7 +408,7 @@ NOTE: This method is strict and will only validate numbers without decimal place print "The number: [$number] is valid!\n"; } -=head2 Parameters; +Parameters; =head3 number (required) @@ -458,7 +458,7 @@ sub is_positive_integer This method takes a subnet string and checks to see if it is a valid IPv4 address or CIDR notation. It returns 'C<< 1 >>' if it is a valid address. Otherwise it returns 'C<< 0 >>'. -=head2 Parameters; +Parameters; =head3 subnet (required) @@ -520,7 +520,7 @@ NOTE: This method is strict and will only validate UUIDs that are lower case! print "The UUID: [$string] is valid!\n"; } -=head2 Parameters; +Parameters; =head3 uuid (required) diff --git a/cgi-bin/home b/cgi-bin/home index a14a502e1..779a31ad1 100755 --- a/cgi-bin/home +++ b/cgi-bin/home @@ -30,6 +30,7 @@ my $anvil = Anvil::Tools->new(); # Set the log level to 2. Setting 3 slows he program down a LOT. $anvil->Log->level({set => 2}); +$anvil->Log->secure({set => 0}); # Read the config and then connect to the database. $anvil->Storage->read_config(); @@ -133,7 +134,7 @@ my $right_buttons = $anvil->Template->get({file => "main.html", name => "button_ configure_button => $anvil->data->{sys}{users}{user_name} ? $anvil->Template->get({file => "main.html", name => "configure_button_on"}) : $anvil->Template->get({file => "main.html", name => "configure_button_off"}), user_button => $anvil->data->{sys}{users}{user_name} ? $anvil->Template->get({file => "main.html", name => "user_button_on"}) : $anvil->Template->get({file => "main.html", name => "user_button_off"}), }}); -my $footer = $anvil->Template->get({file => "main.html", name => "footer", variables => { +my $footer = $anvil->Template->get({file => "main.html", name => "footer", variables => { user => $anvil->data->{sys}{users}{user_name} ? "#!string!message_0034!#" : " ", }}); @@ -261,10 +262,40 @@ sub process_sync_page { my ($anvil) = @_; + # Setup some CGI values we might use. + $anvil->data->{cgi}{new_peer_access}{value} = "" if not defined $anvil->data->{cgi}{new_peer_access}{value}; + $anvil->data->{cgi}{new_peer_password}{value} = "" if not defined $anvil->data->{cgi}{new_peer_password}{value}; + $anvil->data->{cgi}{save}{value} = "" if not defined $anvil->data->{cgi}{save}{value}; + $anvil->data->{cgi}{confirm}{value} = "" if not defined $anvil->data->{cgi}{confirm}{value}; + + # This handles checkboxes + if (defined $anvil->data->{cgi}{new_peer_ping}{value}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ">> cgi::new_peer_ping::value" => $anvil->data->{cgi}{new_peer_ping}{value} }}); + $anvil->data->{cgi}{new_peer_ping}{value} = $anvil->data->{cgi}{new_peer_ping}{value} eq "off" ? 0 : 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< cgi::new_peer_ping::value" => $anvil->data->{cgi}{new_peer_ping}{value} }}); + } + else + { + $anvil->data->{cgi}{new_peer_ping}{value} = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::new_peer_ping::value" => $anvil->data->{cgi}{new_peer_ping}{value} }}); + } + if (defined $anvil->data->{cgi}{new_peer_bidirection}{value}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ">> cgi::new_peer_bidirection::value" => $anvil->data->{cgi}{new_peer_bidirection}{value} }}); + $anvil->data->{cgi}{new_peer_bidirection}{value} = $anvil->data->{cgi}{new_peer_bidirection}{value} eq "off" ? 0 : 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< cgi::new_peer_bidirection::value" => $anvil->data->{cgi}{new_peer_bidirection}{value} }}); + } + else + { + $anvil->data->{cgi}{new_peer_bidirection}{value} = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::new_peer_bidirection::value" => $anvil->data->{cgi}{new_peer_bidirection}{value} }}); + } + # Are we adding a new peer? - if ($anvil->data->{cgi}{action}{value} eq "add") + if (($anvil->data->{cgi}{new_peer_access}{value}) && ($anvil->data->{cgi}{new_peer_password}{value} ne "")) { - #add_sync_peer($anvil); + add_sync_peer($anvil); } elsif ($anvil->data->{cgi}{action}{value} eq "remove") { @@ -372,13 +403,130 @@ sub process_sync_page # Build the menu. $anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "striker-sync", variables => { - inbound_table => $inbound_table, - peer_table => $peer_table, + inbound_table => $inbound_table, + peer_table => $peer_table, + new_peer_access => defined $anvil->data->{cgi}{new_peer_access}{value} ? $anvil->data->{cgi}{new_peer_access}{value} : "", + new_peer_password => defined $anvil->data->{cgi}{new_peer_password}{value} ? $anvil->data->{cgi}{new_peer_password}{value} : "", }}); return(0); } +# This adds a new peer to anvil.conf. +sub add_sync_peer +{ + my ($anvil) = @_; + + # Break up the user, host and port. If anything goes wrong, we'll set an error and send it back. + my $user = $anvil->data->{sys}{database}{user}; + my $host = $anvil->data->{cgi}{new_peer_access}{value}; + my $name = $anvil->data->{sys}{database}{name}; + my $port = 5432; + my $ssh_tcp = 22; + my $peer_uuid = ""; + my $peer_host = ""; + if ($anvil->data->{cgi}{new_peer_access}{value} =~ /,ssh=(\d+)$/) + { + $ssh_tcp = $1; + $anvil->data->{cgi}{new_peer_access}{value} =~ s/,ssh=\d+$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ssh_tcp => $ssh_tcp, + "cgi::new_peer_access::value" => $anvil->data->{cgi}{new_peer_access}{value}, + }}); + } + if ($anvil->data->{cgi}{new_peer_access}{value} =~ /^(.*?)\@(.*?):(\d+)$/) + { + $user = $1; + $host = $2; + $port = $3; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + host => $host, + port => $port, + user => $user, + }}); + } + elsif ($anvil->data->{cgi}{new_peer_access}{value} =~ /^(.*?)\@(.*?)$/) + { + $user = $1; + $host = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + host => $host, + user => $user, + }}); + } + elsif ($anvil->data->{cgi}{new_peer_access}{value} =~ /^(.*?):(\d+)$/) + { + $host = $1; + $port = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + host => $host, + port => $port, + }}); + } + + # Is the host a domain or IP? + # If so, and 'bi-directional' is set, verify we can ssh into the peer. + if ((not $anvil->Validate->is_domain_name({name => $host})) or + (not $anvil->Validate->is_ipv4({ip => $host})) or + ($port < 1) or + ($port > 65536)) + { + # Bad host. + $anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "striker_warning_0002"}) }}); + } + else + { + # Can we connect to the peer? + (my $error, $peer_uuid) = $anvil->Remote->call({ + password => $anvil->data->{cgi}{new_peer_password}{value}, + target => $ssh_tcp != 22 ? $host.":".$ssh_tcp : $host, + shell_call => $anvil->data->{path}{exe}{dmidecode}." --string system-uuid", + }); + if ($error) + { + # No access + $anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "striker_warning_0003"}) }}); + } + else + { + # We got the peer's UUID. Get the hostname as well. + $peer_uuid = lc($peer_uuid); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_uuid => $peer_uuid }}); + + (my $error, $peer_host) = $anvil->Remote->call({ + password => $anvil->data->{cgi}{new_peer_password}{value}, + target => $ssh_tcp != 22 ? $host.":".$ssh_tcp : $host, + shell_call => $anvil->data->{path}{exe}{hostnamectl}." --static", + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host => $peer_host }}); + } + } + + # Lastly, verify we can access the peer database. This will involve writting out a .pgpass file, then making a local system call. + my $password = $anvil->data->{cgi}{new_peer_password}{value}; + $password =~ s/:/\:/g; + my $pgpass = $host.":".$port.":".$name.":".$user.":".$password; + + # Write out the .pgpass file. + # TODO: Left off here, write out .pgpass, set the mode to 0600, then call 'psql --host 10.1.4.1 --port 5432 --dbname anvil --username admin --no-password --command "SELECT 1" ' + + my $db_access = $anvil->System->call({uuid => $peer_uuid}); + + # Is it confirmed? + if (not $anvil->data->{cgi}{confirm}{value}) + { + # Show the screen the confirm the addition. + $anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "confirm-new-peer", variables => { + user + }}); + } + else + { + } + + return(0); +} + # This shows the menus for configuring Striker. sub configure_striker { diff --git a/html/skins/alteeve/striker.html b/html/skins/alteeve/striker.html index 12a486b35..5e2a1e395 100644 --- a/html/skins/alteeve/striker.html +++ b/html/skins/alteeve/striker.html @@ -1,6 +1,65 @@ + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ About to add a new peer +
+ Striker User: + + #!variable!user!# +
+ Host: + + #!variable!host!# +
+ Port: + + #!variable!port!# +
+ Ping before Connect: + + #!variable!ping!# +
+ Bi-directional: + + #!variable!bidirectional!# +
+ When the peer is added, all data from this host will be copied to the peer's database. Depending on how much data this is, how fast the connection is, and how fast the local machine is, this sync process could take a little time. +
+ - +
@@ -156,10 +215,11 @@ + + @@ -190,7 +252,8 @@ #!string!striker_0075!#:   - #!string!striker_0076!# + #!string!striker_0076!#
+ #!string!striker_0077!# @@ -289,4 +352,3 @@ - diff --git a/share/words.xml b/share/words.xml index 7b9292d2a..061a89f7b 100644 --- a/share/words.xml +++ b/share/words.xml @@ -400,6 +400,7 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st When checked, the peer will be configure to add the local database as a peer at the same time that we add it to this system. Access admin', and the default port is '5432'. If the peer uses these, then you only need to specify the IP address or hostname of the peer. If the user name is not 'admin', then you need to use the format 'user@host. If the TCP port is not '5432', then you need to use 'host:port. If both user and port are different, use the format 'user@host:port'.]]> + 22', you can append: ',ssh=X' where 'X' is the SSH TCP port.]]> Configure Network @@ -407,6 +408,8 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st The IP address will change. You will need to reconnect after applying these changes. + The access information appears to not be valid. + Test access to the peer (using SSH) failed. There may be details in the log file. There are not enough network interfaces on this machine. You have: [#!variable!interface_count!#] interface(s), and you need at least: [#!variable!required_interfaces_for_single!#] interfaces to connect to the requested networks (one for Back-Channel and one for each Internet-Facing network).