| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  | #!/usr/bin/perl -w | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | use strict; | 
					
						
							| 
									
										
										
										
											2020-11-16 14:08:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | use CGI; | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  | use Git::Repository; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # File to store cloud credentials | 
					
						
							|  |  |  | my $config_file = "/opt/ssrf/ssrf.conf"; | 
					
						
							|  |  |  | # Where to store the git repository | 
					
						
							|  |  |  | my $git_dir = "/opt/ssrf/gitdir"; | 
					
						
							|  |  |  | # Downloader binary | 
					
						
							|  |  |  | my $downloader = "/home/pi/src/subsurface/build/subsurface-downloader"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | my %conf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Use unbuffered output | 
					
						
							|  |  |  | $| = 1; | 
					
						
							| 
									
										
										
										
											2020-11-16 14:08:31 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-27 23:14:13 +01:00
										 |  |  | # Setup some environemnt variables to make subsurface startup happy | 
					
						
							|  |  |  | $ENV{HOME} = '/tmp'; | 
					
						
							|  |  |  | $ENV{LOGNAME} = 'www-data'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-16 14:08:31 +01:00
										 |  |  | my $q = CGI->new; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | print $q->header('text/html'); | 
					
						
							|  |  |  | print $q->img({src => 'https://subsurface-divelog.org/wp-content/uploads/2015/10/subsurface-icon1.png'}); | 
					
						
							|  |  |  | print $q->h1("Subsurface"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  | printf "Reading config file $config_file\n"; | 
					
						
							|  |  |  | open CONF, $config_file || die "Cannot read $config_file:$!"; | 
					
						
							|  |  |  | while (<CONF>) { | 
					
						
							| 
									
										
										
										
											2020-11-28 14:33:20 +01:00
										 |  |  |   s/#.*$//; | 
					
						
							|  |  |  |   if (/^\s*(\w+)\s*=\s*(\S.*)$/) { | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  |     $conf{$1} = $2; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | close CONF; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-16 14:08:31 +01:00
										 |  |  | my %dcs; | 
					
						
							|  |  |  | &load_supported_dcs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | print $q->start_form(); | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-28 14:33:20 +01:00
										 |  |  | my $action = $q->param("action") || "start"; | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | if ($action eq "config") { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Enter cloud credentials | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   print "Subsurface cloud user name (typically your email address): ", $q->textfield(-name => 'username', -default => $conf{username}); | 
					
						
							|  |  |  |   print "<br>Subsurface cloud password: ", $q->password_field(-name => "password"); | 
					
						
							|  |  |  |   &next_action("writeconfig"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } elsif ($action eq "writeconfig") { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   $conf{username} = $q->param("username"); | 
					
						
							|  |  |  |   $conf{username} =~ s/\s//g; | 
					
						
							|  |  |  |   $conf{password} = $q->param("password"); | 
					
						
							|  |  |  |   $conf{password} =~ s/\s//g; | 
					
						
							|  |  |  |   &write_conf; | 
					
						
							|  |  |  |   &next_action("start"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } elsif ($action eq "setmanufacturer") { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Now we know the manufacturer, ask for model | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-16 14:08:31 +01:00
										 |  |  |   print $q->hidden(-name => "Manufacturer", -default => $q->param("Manufacturer")); | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  |   print "Select ",$q->param("Manufacturer")," model:"; | 
					
						
							| 
									
										
										
										
											2020-11-28 14:33:20 +01:00
										 |  |  |   print $q->popup_menu(-name => "Product", -values => $dcs{$q->param("Manufacturer")}, -default => $conf{lastProduct}); | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  |   &next_action("setproduct") | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  | } elsif ($action eq "setproduct") { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Now we know the model as well, ask for mount point | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   print $q->hidden(-name => "Manufacturer", -default => $q->param("Manufacturer")); | 
					
						
							|  |  |  |   print $q->hidden(-name => "Product", -default => $q->param("Product")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   opendir DIR, "/dev"; | 
					
						
							| 
									
										
										
										
											2020-11-28 14:33:20 +01:00
										 |  |  |   my @devices = sort {$a cmp $b} map {"/dev/$_"} (grep {/ttyUSB|ttyS|ttyACM|rfcom/} grep {!/^\./} (readdir DIR)); | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  |   closedir DIR; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-28 14:33:20 +01:00
										 |  |  |   open MOUNTS, "/proc/mounts"; | 
					
						
							|  |  |  |   while (<MOUNTS>) { | 
					
						
							|  |  |  |     my ($device, $mountpoint) = split /\s/; | 
					
						
							|  |  |  |     if ($device =~ /dev/) { | 
					
						
							|  |  |  |       push @devices, $mountpoint; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-11-16 14:08:31 +01:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-11-28 14:33:20 +01:00
										 |  |  |   close MOUNTS; | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  |    | 
					
						
							| 
									
										
										
										
											2020-11-28 14:33:20 +01:00
										 |  |  |   print $q->popup_menu(-name => "Mount point", -values => \@devices, -default => $conf{lastMountpoint}); | 
					
						
							|  |  |  |   &next_action("startdownload"); | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-28 14:33:20 +01:00
										 |  |  | } elsif ($action eq "startdownload") { | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-28 14:33:20 +01:00
										 |  |  |   $conf{lastManufacturer} = $q->param("Manufacturer"); | 
					
						
							|  |  |  |   $conf{lastProduct} = $q->param("Product"); | 
					
						
							|  |  |  |   $conf{lastMountpoint} = $q->param("Mount point"); | 
					
						
							|  |  |  |   &write_conf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   &run_download; | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  |   &next_action("start"); | 
					
						
							| 
									
										
										
										
											2020-11-16 14:08:31 +01:00
										 |  |  | } else { | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   # This is the mode we start up in | 
					
						
							|  |  |  |    | 
					
						
							| 
									
										
										
										
											2020-11-16 14:08:31 +01:00
										 |  |  |   print "Select dive computer manufacturer:"; | 
					
						
							| 
									
										
										
										
											2020-11-28 14:33:20 +01:00
										 |  |  |   print $q->popup_menu(-name => "Manufacturer", -values => [sort keys %dcs], -default => $conf{lastManufacturer}); | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  |   &next_action("setmanufacturer") | 
					
						
							| 
									
										
										
										
											2020-11-16 14:08:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  | print $q->br(),$q->submit(-name => "  OK  "); | 
					
						
							| 
									
										
										
										
											2020-11-16 14:08:31 +01:00
										 |  |  | print $q->end_form(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  | print $q->br(), $q->a({-href => $q->url() . "?action=config"}, "Configure cloud credentials"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-16 14:08:31 +01:00
										 |  |  | sub load_supported_dcs { | 
					
						
							| 
									
										
										
										
											2024-01-27 23:14:13 +01:00
										 |  |  |   open IN, "$downloader --list-dc|" || die "Cannot run $downloader: $!"; | 
					
						
							| 
									
										
										
										
											2020-11-16 14:08:31 +01:00
										 |  |  |    | 
					
						
							|  |  |  |   while(<IN>) { | 
					
						
							|  |  |  |     last if /Supported dive computers:/; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   while(<IN>) { | 
					
						
							|  |  |  |     last unless /\S/; | 
					
						
							| 
									
										
										
										
											2020-11-28 14:33:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-16 14:08:31 +01:00
										 |  |  |     my ($manufacturer, $products) = /"([^:]+):\s+([^"]+)"/; | 
					
						
							| 
									
										
										
										
											2020-11-28 14:33:20 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     next unless defined $products; | 
					
						
							| 
									
										
										
										
											2020-11-16 14:08:31 +01:00
										 |  |  |     $products =~ s/\([^\)]*\)//g; | 
					
						
							|  |  |  |     my @products  = split /,\s*/, $products; | 
					
						
							|  |  |  |     $dcs{$manufacturer} = \@products; | 
					
						
							| 
									
										
										
										
											2020-11-28 14:33:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-16 14:08:31 +01:00
										 |  |  |   } | 
					
						
							|  |  |  |   close IN; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-27 22:21:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | sub write_conf { | 
					
						
							|  |  |  |   print "Writing config file\n"; | 
					
						
							|  |  |  |   open CONFW, ">$config_file" || die "Cannot write $config_file:$!"; | 
					
						
							|  |  |  |   foreach my $key (keys %conf) { | 
					
						
							|  |  |  |     print CONFW "$key = $conf{$key}\n"; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   close CONFW; | 
					
						
							|  |  |  |   print "Done\n"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | sub next_action { | 
					
						
							|  |  |  |   my $next = shift; | 
					
						
							|  |  |  |   $q->param(action => $next); | 
					
						
							|  |  |  |   print $q->hidden( | 
					
						
							|  |  |  | 		   -name => "action", | 
					
						
							|  |  |  | 		   -value => $next); | 
					
						
							|  |  |  |   return; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-11-28 14:33:20 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | sub run_download { | 
					
						
							|  |  |  |   # Do the actual download | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   my $repo; | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   # Does the repo exist? | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   if (-d $git_dir) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # ... yes, pull latest version | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     $repo = Git::Repository->new( work_tree => $git_dir); | 
					
						
							|  |  |  |     print "Pulling latest version from cloud."; | 
					
						
							|  |  |  |     print $q->pre($repo->run("pull")); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # ... no, clone it | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     my $en_username = $conf{username}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # We need to escape the @ in the username to be able to encode it in the URL. | 
					
						
							|  |  |  |     # Note: If we fail, the password gets written to /var/log/apache/error.log, | 
					
						
							|  |  |  |     # Maybe there is a better way to pass the password to git... | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     $en_username =~ s/\@/%40/g; | 
					
						
							|  |  |  |     my $git_url = 'https://' . $en_username . ':' . $conf{password} . '@cloud.subsurface-divelog.org//git/' . $conf{username}; | 
					
						
							|  |  |  |     print "Cloning repository"; | 
					
						
							|  |  |  |     print $q->pre(Git::Repository->run( clone => $git_url, $git_dir)); | 
					
						
							|  |  |  |     $repo = Git::Repository->new( work_tree => $git_dir ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Assemble the command with all arguments | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   my $command = "$downloader --dc-vendor=" . $q->param('Manufacturer') . | 
					
						
							|  |  |  | 		" --dc-product=" . $q->param('Product') . | 
					
						
							|  |  |  | 		" --device=" . $q->param("Mount point") . | 
					
						
							|  |  |  | 		' ' . $git_dir . | 
					
						
							|  |  |  | 		'/[' . $conf{username} . ']'; | 
					
						
							|  |  |  |   print $q->pre($command); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # ... and run it | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   print $q->pre(`$command`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # Push back to the cloud | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   print "Checkout user branch"; | 
					
						
							|  |  |  |   print $q->pre($repo->run("checkout", $conf{username})); | 
					
						
							|  |  |  |   print "Push changes to cloud"; | 
					
						
							|  |  |  |   print $q->pre($repo->run("push", "origin", $conf{username})); | 
					
						
							|  |  |  | } |