Skip to content

Instantly share code, notes, and snippets.

@fabiomontefuscolo
Last active December 22, 2020 21:07
Show Gist options
  • Save fabiomontefuscolo/24059c9d4c3d4554cdd9b4eaec2d9dc1 to your computer and use it in GitHub Desktop.
Save fabiomontefuscolo/24059c9d4c3d4554cdd9b4eaec2d9dc1 to your computer and use it in GitHub Desktop.
Virtualmin syncthing install script
our (%in, %config);
use warnings;
use XML::LibXML;
sub script_syncthing_desc
{
return "Syncthing";
}
sub script_syncthing_uses
{
return ( "syncthing", "apache2-utils" );
}
sub script_syncthing_longdesc
{
return "Syncthing is an application that lets you synchronize your files across multiple devices.";
}
sub script_syncthing_versions
{
return ( "1.1.4" );
}
sub script_syncthing_can_upgrade
{
return 1;
}
sub script_syncthing_release
{
return 1;
}
sub script_syncthing_gpl
{
return 1;
}
sub script_syncthing_category
{
return "Network";
}
sub script_syncthing_site
{
return 'https://syncthing.net/';
}
sub script_syncthing_depends
{
local ($d, $ver) = @_;
local @rv;
my $syncthing = &has_command($config{"syncthing_cmd"} || "syncthing");
$syncthing || push(@rv, "The syncthing package is not installed");
return @rv;
}
sub script_syncthing_perl_modules
{
return ("XML::LibXML");
}
sub script_syncthing_params
{
local ($d, $ver, $upgrade) = @_;
local $rv;
my $config_dir = "$d->{'home'}/.config/syncthing";
my $config_file = "$config_dir/config.xml";
my $user = $d->{'user'};
my $password = "";
if ( -f $config_file ) {
my $dom = XML::LibXML->load_xml(location => $config_file);
$user = $dom->findnodes('/configuration/gui/user/text()') || $user;
$password = $dom->findnodes('/configuration/gui/password/text()');
}
if ($upgrade) {
$rv .= &ui_table_row(" ", " ");
$rv .= &ui_table_row("", "<strong>Syncthing authentication</strong>");
$rv .= &ui_table_row("User", $user);
} else {
$rv .= &ui_table_row(" ", " ");
$rv .= &ui_table_row("", "<strong>Syncthing authentication</strong>");
$rv .= &ui_table_row("User", &ui_textbox("user", $user));
$rv .= &ui_table_row("Password", &ui_password("password"));
}
return $rv;
}
sub script_syncthing_parse
{
local ($d, $ver, $in, $upgrade) = @_;
if ($upgrade) {
return $upgrade->{'opts'};
}
return {
"user" => $in->{'user'} || $d->{'user'},
"password" => $in->{'password'}
};
}
sub script_syncthing_check
{
local ($d, $ver, $opts, $upgrade) = @_;
my $rv;
my $user = $opts->{'user'} || $d->{'user'};
if (! $user || length($user) < 3) {
$rv .= "Please, provide a valid username (minumum of 3 chars)" . "<br/>";
}
my $password = $opts->{'password'};
if (! $password || length($password) < 6) {
$rv .= "Please, provide a valid password (minimum of 6 chars)" . "<br/>";
}
return $rv;
}
sub script_syncthing_files
{
}
sub script_syncthing_install
{
local ($d, $version, $opts, $files, $upgrade, $domuser, $dompass) = @_;
local ($out, $ex);
my $syncthing = &has_command($config{'syncthing_cmd'} || "/usr/bin/syncthing");
my $syncthing_web_path = "/syncthing/";
my $syncthing_ext_url = "http://$d->{'dom'}$syncthing_web_path";
my $config_dir = "$d->{'home'}/.config/syncthing";
my $config_file = "$config_dir/config.xml";
my $out = &run_as_domain_user($d, "$syncthing -generate=$config_dir");
if (! -r $config_file) {
return (0, "Failed to create syncthing configuration files");
}
my $config_dom = XML::LibXML->load_xml(location => $config_file);
my ($el_gui) = $config_dom->findnodes('/configuration/gui');
# setting user
my ($el_user) = $el_gui->findnodes('user');
if (! $el_user) {
$el_user = $config_dom->createElement('user');
$el_gui->appendChild($el_user);
}
$el_user->removeChildNodes();
$el_user->appendText($opts->{'user'} || $d->{'user'});
# setting password
my ($el_password) = $el_gui->findnodes('password');
if (! $el_password) {
$el_password = $config_dom->createElement('password');
$el_gui->appendChild($el_password);
}
my $password_hash = substr(`htpasswd -bnBC 10 "" $opts->{'password'}`, 1);
$password_hash =~ s/^\s+|\s+$//g;
$el_password->removeChildNodes();
$el_password->appendText($password_hash);
# update syncthing xml
$config_dom->toFile($config_file);
my $syncthing_int_url = $config_dom->findnodes('/configuration/gui/address/text()');
local $conf = &apache::get_config();
local @ports = ( $d->{'web_port'}, $d->{'ssl'} ? ( $d->{'web_sslport'} ) : ( ) );
foreach my $port (@ports) {
local ($virt, $vconf) = &get_apache_virtual($d->{'dom'}, $port);
next if (!$virt);
local @pp = &apache::find_directive("ProxyPass", $vconf);
local @ppr = &apache::find_directive("ProxyPassReverse", $vconf);
push(@pp, "$syncthing_web_path http://$syncthing_int_url/");
push(@ppr, "$syncthing_web_path http://$syncthing_int_url/");
&apache::save_directive("ProxyPass", \@pp, $vconf, $conf);
&apache::save_directive("ProxyPassReverse", \@ppr, $vconf, $conf);
&flush_file_lines($virt->{'file'});
}
# Create an init script
my $cmd = &get_syncthing_start_cmd($d, $opts);
my $userd = $d->{'parent'} ? &get_domain($d->{'parent'}) : $d;
if (&foreign_installed("init") && $userd && $userd->{'unix'} && !$upgrade) {
my $name = "syncthing-$d->{'user'}";
my $killcmd = "kill `pgrep -f $syncthing`";
&foreign_require("init");
my $opts = { };
if ($init::init_mode eq 'upstart' || $init::init_mode eq 'systemd') {
# Init system will background it
$opts->{'fork'} = 0;
}
else {
$cmd .= "&";
}
&init::enable_at_boot(
$name,
"Starting syncthing for $d->{'user'}",
&command_as_user($userd->{'user'}, 0, $cmd),
&command_as_user($userd->{'user'}, 0, $killcmd),
undef,
$opts,
);
}
# Start the server process
&script_syncthing_start_server($d, $opts);
&register_post_action(\&restart_apache);
return (1, "Syncthing is installed for $domuser. Try accessing the adming at"
. " <a href=\"$syncthing_ext_url\">$syncthing_ext_url</a> with the password '$password'");
}
sub script_syncthing_start_server
{
local ($d, $opts) = @_;
my $cmd = &get_syncthing_start_cmd($d, $opts);
&run_as_domain_user($d, $cmd, 1);
}
sub script_syncthing_stop
{
local ($d, $sinfo) = @_;
my $opts = $sinfo->{'opts'};
if (!$opts->{'port'}) {
return undef;
};
&script_syncthing_stop_server($d, $opts);
&foreign_require("init");
my $name = "syncthing-$d->{'user'}";
if (defined(&init::delete_at_boot)) {
&init::delete_at_boot($name)
}
else {
&init::disable_at_boot($name);
}
}
sub script_syncthing_stop_server
{
local ($d, $opts) = @_;
my $syncthing = &has_command($config{'syncthing_cmd'} || "/usr/bin/syncthing");
my $killcmd = "kill `pgrep -f $syncthing`";
&run_as_domain_user($d, $killcmd);
}
sub script_syncthing_uninstall
{
local ($d, $version, $opts) = @_;
&require_apache();
local $conf = &apache::get_config();
local @ports = ( $d->{'web_port'}, $d->{'ssl'} ? ( $d->{'web_sslport'} ) : ( ) );
my $syncthing_web_path = "/syncthing/";
foreach my $port (@ports) {
local ($virt, $vconf) = &get_apache_virtual($d->{'dom'}, $port);
next if (!$virt);
local @pp = &apache::find_directive("ProxyPass", $vconf);
local ($pp) = grep { $_ =~ /^\Q$syncthing_web_path\E\s/ } @pp;
if ($pp) {
@pp = grep { $_ ne $pp } @pp;
&apache::save_directive("ProxyPass", \@pp, $vconf, $conf);
&flush_file_lines($virt->{'file'});
}
local @ppr = &apache::find_directive("ProxyPassReverse", $vconf);
local ($ppr) = grep { $_ =~ /^\Q$syncthing_web_path\E\s/ } @ppr;
if ($ppr) {
@ppr = grep { $_ ne $ppr } @ppr;
&apache::save_directive("ProxyPassReverse", \@ppr, $vconf, $conf);
&flush_file_lines($virt->{'file'});
}
}
&script_syncthing_stop($d, { 'opts' => $opts });
&register_post_action(\&restart_apache);
return (1, "Syncthing is disabled now");
}
sub get_syncthing_start_cmd
{
my ($d, $opts) = @_;
my $syncthing = &has_command($config{'syncthing_cmd'} || "/usr/bin/syncthing");
my $cmd = "$syncthing -no-browser -no-restart -logflags=0";
return $cmd;
}
1;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment