2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-19 12:46:03 +00:00

01_FHEMWEB.js: add rescueDialog

git-svn-id: https://svn.fhem.de/fhem/trunk@26494 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig 2022-10-07 15:48:42 +00:00
parent fade4763e3
commit afc7346a5e
2 changed files with 202 additions and 15 deletions

View File

@ -189,16 +189,17 @@ FHEMWEB_Initialize($)
menuEntries menuEntries
mainInputLength mainInputLength
nameDisplay nameDisplay
nrAxis
ploteditor:always,onClick,never ploteditor:always,onClick,never
plotfork:1,0 plotfork:1,0
plotmode:gnuplot-scroll,gnuplot-scroll-svg,SVG plotmode:gnuplot-scroll,gnuplot-scroll-svg,SVG
plotEmbed:2,1,0 plotEmbed:2,1,0
plotsize plotsize
plotWeekStartDay:0,1,2,3,4,5,6 plotWeekStartDay:0,1,2,3,4,5,6
nrAxis
redirectCmds:0,1 redirectCmds:0,1
redirectTo redirectTo
refresh refresh
rescueDialog:1,0
reverseLogs:0,1 reverseLogs:0,1
roomIcons:textField-long roomIcons:textField-long
showUsedFiles:0,1 showUsedFiles:0,1
@ -1247,7 +1248,7 @@ FW_dataAttr()
addParam($FW_wname, "styleData", ""). addParam($FW_wname, "styleData", "").
addParam("global", "language", "EN"). addParam("global", "language", "EN").
"data-availableJs='$FW_fhemwebjs' ". "data-availableJs='$FW_fhemwebjs' ".
"data-webName='$FW_wname '"; "data-webName='$FW_wname' ";
} }
sub sub
@ -1742,27 +1743,44 @@ FW_roomOverview($)
my $sfx = AttrVal("global", "language", "EN"); my $sfx = AttrVal("global", "language", "EN");
$sfx = ($sfx eq "EN" ? "" : "_$sfx"); $sfx = ($sfx eq "EN" ? "" : "_$sfx");
my @list = ( my @list = (
"Everything", "$FW_ME?room=all", 'Everything', "$FW_ME?room=all",
"", "", '', '',
"Commandref", "$FW_ME/docs/commandref${sfx}.html", 'Commandref', "$FW_ME/docs/commandref${sfx}.html",
"Remote doc", "http://fhem.de/fhem.html#Documentation", 'Remote doc', 'http://fhem.de/fhem.html#Documentation',
"Edit files", "$FW_ME?cmd=style%20list", 'Edit files', "$FW_ME?cmd=style%20list",
"Select style", "$FW_ME?cmd=style%20select", 'Select style', "$FW_ME?cmd=style%20select",
"Event monitor", "$FW_ME?cmd=style%20eventMonitor", 'Event monitor', "$FW_ME?cmd=style%20eventMonitor",
"", ""); '', '');
my $lastname = ","; # Avoid double "".
my $lfn = "Logfile"; my $lfn = "Logfile";
if($defs{$lfn}) { # Add the current Logfile to the list if defined if($defs{$lfn}) { # Add the current Logfile to the list if defined
my @l = FW_fileList($defs{$lfn}{logfile},1); my @l = FW_fileList($defs{$lfn}{logfile},1);
my $fn = pop @l; my $fn = pop @l;
splice @list, 4,0, ("Logfile", splice @list, 4,0, ('Logfile',
"$FW_ME/FileLog_logWrapper?dev=$lfn&type=text&file=$fn"); "$FW_ME/FileLog_logWrapper?dev=$lfn&type=text&file=$fn");
} }
if(AttrVal($FW_wname, 'rescueDialog', undef)) {
my $pid = $defs{$FW_wname}{rescuePID};
$pid = 0 if(!$pid || !kill(0,$pid));
my $key="";
if(!-r "certs/fhemrescue.pub") {
mkdir("certs");
`ssh-keygen -N "" -t ed25519 -f certs/fhemrescue`;
}
if(open(my $fh, "certs/fhemrescue.pub")) {
$key = <$fh>;
close($fh);
}
splice @list, @list-2,0, ('Rescue',
"javascript:FW_rescueClient(\"$pid\",\"$key\")");
}
my @me = split(",", AttrVal($FW_wname, "menuEntries", "")); my @me = split(",", AttrVal($FW_wname, "menuEntries", ""));
push @list, @me, "", "" if(@me); push @list, @me, "", "" if(@me);
my $lastname = ",";
for(my $idx = 0; $idx < @list; $idx+= 2) { for(my $idx = 0; $idx < @list; $idx+= 2) {
next if($FW_hiddenroom{$list[$idx]} || $list[$idx] eq $lastname); next if($FW_hiddenroom{$list[$idx]} || $list[$idx] eq $lastname);
push @list1, $list[$idx]; push @list1, $list[$idx];
@ -3445,12 +3463,16 @@ sub
FW_Set($@) FW_Set($@)
{ {
my ($hash, @a) = @_; my ($hash, @a) = @_;
my %cmd = ("rereadicons" => 1, "clearSvgCache" => 1); my %cmd = ("rereadicons" => ":noArg", "clearSvgCache" => ":noArg");
if(AttrVal($hash->{NAME}, "rescueDialog", "")) {
$cmd{"rescueStart"} = "";
$cmd{"rescueTerminate"} = ":noArg";
}
return "no set value specified" if(@a < 2); return "no set value specified" if(@a < 2);
return ("Unknown argument $a[1], choose one of ". return ("Unknown argument $a[1], choose one of ".
join(" ", map { "$_:noArg" } sort keys %cmd)) join(" ", map { "$_$cmd{$_}" } sort keys %cmd))
if(!$cmd{$a[1]}); if(!defined($cmd{$a[1]}));
if($a[1] eq "rereadicons") { if($a[1] eq "rereadicons") {
my @dirs = keys %FW_icons; my @dirs = keys %FW_icons;
@ -3459,6 +3481,7 @@ FW_Set($@)
FW_readIcons($d); FW_readIcons($d);
} }
} }
if($a[1] eq "clearSvgCache") { if($a[1] eq "clearSvgCache") {
my $cDir = "$FW_dir/SVGcache"; my $cDir = "$FW_dir/SVGcache";
if(opendir(DH, $cDir)) { if(opendir(DH, $cDir)) {
@ -3468,6 +3491,31 @@ FW_Set($@)
return "Can't open $cDir: $!"; return "Can't open $cDir: $!";
} }
} }
if($a[1] eq "rescueStart") {
return "error: rescueStart needs two arguments: host and port"
if(!$a[2] || !$a[3] || $a[3] !~ m/[0-9]{1,5}/ || $a[3] > 65536);
return "error: rescue process is running with PID $hash->{rescuePID}"
if($hash->{rescuePID} && kill(0, $hash->{rescuePID}));
return "error: certificate certs/fhemrescue is not available"
if(! -r "certs/fhemrescue");
$hash->{rescuePID} = fhemFork();
return "error: cannot fork rescue pid\n"
if($hash->{rescuePID} == -1);
return undef if($hash->{rescuePID}); # Parent
my $cmd = "exec ssh -N -R0.0.0.0:18083:localhost:$hash->{PORT} ".
"-i certs/fhemrescue -p$a[3] fhemrescue\@$a[2]";
Log 1, "Starting $cmd";
exec($cmd);
}
if($a[1] eq "rescueTerminate") {
return "error: nothing to terminate"
if(!$hash->{rescuePID});
kill(15, $hash->{rescuePID});
delete($hash->{rescuePID});
}
return undef; return undef;
} }
@ -4206,6 +4254,48 @@ FW_log($$)
seconds). seconds).
</li><br> </li><br>
<a id="FHEMWEB-attr-rescueDialog"></a>
<li>rescueDialog<br>
If set, show a Rescue link in the menu. The goal is to be able to get
help from someone with more knowlege (rescuer), who is then able to
remote control this installation.<br>
After opening the dialog, a key is shown, which is to be sent to the
rescuer. After the rescuer installed the key (see below), the
connection can be established, by entering the adress of the
rescuers server.<br><br>
<b>TODO for the rescuer:</b>
<ul>
<li>Forward a public IP/PORT combination to your SSH server.</li>
<li>create a fhemrescue user on this server, and store the key from
the client:<br>
<ul><code>
useradd -d /tmp -s /bin/false fhemrescue<br>
echo "KEY_FROM_THE_CLIENT" > /etc/sshd/fhemrescue.auth<br>
chown fhemrescue:fhemrescue /etc/sshd/fhemrescue.auth<br>
chmod 600 /etc/sshd/fhemrescue.auth
</code></ul>
</li>
<li>Append to /etc/ssh/sshd_config:<br>
<ul><code>
Match User fhemrescue<br>
<ul>
AllowTcpForwarding remote<br>
PermitTTY no<br>
GatewayPorts yes<br>
ForceCommand /bin/false<br>
AuthorizedKeysFile /etc/ssh/fhemrescue.auth<br>
</ul>
</code></ul>
</li>
<li>Restart sshd, e.g. with systemctl restart sshd
</li>
<li>Tell the client your public IP/PORT.</li>
<li>After the client started the connection in the rescue dialog, you
can access the clients FHEM via your host, port 18083.</li>
</ul>
</li><br>
<a id="FHEMWEB-attr-reverseLogs"></a> <a id="FHEMWEB-attr-reverseLogs"></a>
<li>reverseLogs<br> <li>reverseLogs<br>
Display the lines from the logfile in a reversed order, newest on the Display the lines from the logfile in a reversed order, newest on the
@ -4987,6 +5077,53 @@ FW_log($$)
Refresh, z.B. nach 5 Sekunden. Refresh, z.B. nach 5 Sekunden.
</li><br> </li><br>
<a id="FHEMWEB-attr-rescueDialog"></a>
<li>rescueDialog<br>
Falls gesetzt, im Menue wird ein Rescue Link angezeigt. Das Ziel ist
von jemanden mit mehr Wissen (Retter) Hilfe zu bekommen, indem er die
lokale FHEM-Installation fernsteuert.<br>
Nach &ouml;ffnen des Dialogs wird ein Schl&uuml;ssel angezeigt, was dem
Retter zu schicken ist. Nachdem er diesen Schl&uuml;ssel bei sich
installiert hat, muss seine Adresse (Host und Port) im Dialog
eingetragen werden. Danach kann er die Verbindung fernsteuern.
<br><br>
<b>TODO f&uuml;r den Retter:</b>
<ul>
<li>eine &ouml;ffentliche IP/PORT Kombination zum eigenen SSH Server
weiterleiten.</li>
<li>einen fhemrescue Benutzer auf diesem Server anlegen, und den
Schl&uuml;ssel vom Hilfesuchenden eintragen:<br>
<ul><code>
useradd -d /tmp -s /bin/false fhemrescue<br>
echo "KEY_FROM_THE_CLIENT" > /etc/sshd/fhemrescue.auth<br>
chown fhemrescue:fhemrescue /etc/sshd/fhemrescue.auth<br>
chmod 600 /etc/sshd/fhemrescue.auth
</code></ul>
</li>
<li>Zu /etc/ssh/sshd_config Folgendes hinzuf&uuml;gen:<br>
<ul><code>
Match User fhemrescue<br>
<ul>
AllowTcpForwarding remote<br>
PermitTTY no<br>
GatewayPorts yes<br>
ForceCommand /bin/false<br>
AuthorizedKeysFile /etc/ssh/fhemrescue.auth<br>
</ul>
</code></ul>
</li>
<li>sshd neu starten, z.Bsp. mit systemctl restart sshd
</li>
<li>Dem Hilfesuchenden die &ouml;ffentliche IP/PORT Kombination
mitteilen.</li>
<li>Nachdem der Hilfesuchende diese Daten eingegeben hat, und die
Verbindung gestartet hat, kann die Remote-FHEM-Installation ueber
den eigenen SSH-Server, Port 1803 erreicht wedern.</li>
</ul>
</li><br>
<a id="FHEMWEB-attr-reverseLogs"></a> <a id="FHEMWEB-attr-reverseLogs"></a>
<li>reverseLogs<br> <li>reverseLogs<br>
Damit wird das Logfile umsortiert, die neuesten Eintr&auml;ge stehen Damit wird das Logfile umsortiert, die neuesten Eintr&auml;ge stehen

View File

@ -2239,6 +2239,56 @@ FW_checkNotifydev(reName)
}); });
} }
function
FW_rescueClient(pid, key)
{
let html='<div id="rescueDialog" style="display:none">';
if(!pid || pid == "0") {
html += '<b>Key (send it to the rescuer):</b><br>'+
(key ? '<code>'+key+'</code>' : 'Not found, generate one first');
html += '<br><br>';
}
let buttons = [];
if(key) {
if(pid && pid != "0") {
html += "<div>There is a connection with pid "+pid+"</div><br>";
buttons.push({
text:"Terminate connection",
click:function(){
FW_cmd(FW_root+
"?cmd=set "+$("body").attr("data-webname")+
" rescueTerminate&XHR=1");
setTimeout(function(){ location.reload() }, 1000);
}});
} else {
html += "Address (rescuer will tell you host and port)<br>";
html += "<input type='text' size='20' placeholder='host port' >";
buttons.push({
text:"Start connection",
click:function(){
FW_cmd(FW_root+
"?cmd=set "+$("body").attr("data-webname")+" rescueStart "+
$("#rescueDialog input").val()+"&XHR=1");
setTimeout(function(){ location.reload() }, 1000);
}});
}
}
buttons.push({ text:"Cancel", click:function(){ $(this).dialog('close')} });
$('body').append(html);
$('#rescueDialog').dialog({
modal:true, closeOnEscape:true, width:"auto",
close:function(){ $('#rescueDialog').remove(); },
buttons:buttons
});
}
/* /*
=pod =pod