2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 12:49:34 +00:00

95_Alarm.pm: Escapen von | möglich, csrf und intAt Fixes

git-svn-id: https://svn.fhem.de/fhem/trunk@15919 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
phenning 2018-01-18 04:25:39 +00:00
parent bcd7202d6d
commit 68536172a0
2 changed files with 153 additions and 84 deletions

View File

@ -43,7 +43,7 @@ my $alarmlinkname = "Alarms"; # link text
my $alarmhiddenroom = "AlarmRoom"; # hidden room
my $alarmpublicroom = "Alarm"; # public room
my $alarmno = 8;
my $alarmversion = "3.12";
my $alarmversion = "4.0";
my %alarm_transtable_EN = (
"ok" => "OK",
@ -441,12 +441,16 @@ sub Alarm_getsettings($$$){
my ($hash,$dev,$type) = @_;
my $chg = 0;
my @aval = split('\|',AttrVal($dev, "alarmSettings","|||0:00"),4);
my $avl = AttrVal($dev, "alarmSettings","|||0:00");
$avl = Alarm_escape($avl,"beforesplit");
my @aval = split('\|',$avl,4);
$aval[1] = Alarm_escape($aval[1],"aftersplit");
$aval[2] = Alarm_escape($aval[2],"aftersplit");
if( $type eq "Actor"){
#-- position 0:set by, 1:set func, 2:unset func, 3:delay
#-- position 0:set by level, 1:set func, 2:unset func, 3:delay
if( $aval[0] eq "" || $aval[1] eq "" ){
Log3 $hash, 1, "[Alarm] Settings incomplete for alarmActor $dev";
Log3 $hash, 1, "[Alarm] Settings $avl incomplete for alarmActor $dev";
}
#-- check delay time
if( $aval[3] =~ /^\d+$/ ){
@ -459,7 +463,7 @@ sub Alarm_getsettings($$$){
$aval[3] = sprintf("%02d:%02d",$min,$sec);
}
$chg = 1;
}elsif( $aval[3] !~ /^(\d\d:)?\d\d:\d\d/ ){
}elsif( $aval[3] !~ /^(\d\d:)?\d?\d:\d\d/ ){
Log3 $hash, 1, "[Alarm] Delay time $aval[3] ill defined for alarmActor $dev";
$aval[3] = "0:00";
$chg = 1;
@ -472,6 +476,30 @@ sub Alarm_getsettings($$$){
return @aval;
}
#########################################################################################
#
# Alarm_escape - Helper function to de-escape and to escape action parameters
#
# Parameter hash = hash of Alarm device
# dev = name of device addressed
#
#########################################################################################
sub Alarm_escape($$){
my ($str,$type) = @_;
if( $type eq "beforesplit"){
$str =~ s/\\\|/%7C/g;
}elsif( $type eq "aftersplit"){
$str =~ s/\\//g;
$str =~ s/%7C/\|/g;
}elsif( $type eq "beforehtml"){
$str =~ s/\\//g;
$str =~ s/\|/\\\|/g;
}
return $str;
}
#########################################################################################
#
# Alarm_save
@ -482,7 +510,8 @@ sub Alarm_getsettings($$$){
sub Alarm_save($) {
my ($hash) = @_;
$hash->{DATA}{"savedate"} = sprintf("%s",localtime(time));
my $date = localtime(time);
$hash->{DATA}{"savedate"} = $date;
readingsSingleUpdate( $hash, "savedate", $hash->{DATA}{"savedate"}, 1 );
my $json = JSON->new->utf8;
my $jhash0 = eval{ $json->encode( $hash->{DATA} ) };
@ -610,7 +639,13 @@ sub Alarm_Exec($$$$$){
if( (($stp < $etp) && ($ntp <= $etp) && ($ntp >= $stp)) || (($stp > $etp) && (($ntp <= $etp) || ($ntp >= $stp))) ){
#-- raised by sensor (attribute values have been controlled in CreateNotifiers)
@sta = split('\|', AttrVal($dev, "alarmSettings", ""));
my $avl = AttrVal($dev, "alarmSettings","");
$avl =~ s/\\\|/%7C/g;
@sta = split('\|',$avl);
for( my $i=0;$i<4;$i++ ){
$sta[$i] =~ s/\\//g;
$sta[$i] =~ s/%7C/|/g;
}
if( $sta[2] ){
$mga = $sta[2]." ".AttrVal($name, "level".$level."msg", 0);
#-- replace some parts
@ -651,14 +686,12 @@ sub Alarm_Exec($$$$$){
}elsif( ($act eq "off")||($act eq "cancel") ){
#-- only if this level is active
if( ($xac ne "armed")&&($xac ne "disarmed") ){
#-- TODO: ohne intAt auskommen
#-- deleting all running ats
$dly = sprintf("alarm%1ddly",$level);
foreach my $d (sort keys %intAt ) {
next if( $intAt{$d}{FN} ne "at_Exec" );
$mga = $intAt{$d}{ARG}{NAME};
next if( $mga !~ /$dly\d/);
#Log3 $hash,1,"[Alarm] Killing delayed action $name";
CommandDelete(undef,"$mga");
foreach my $d ( devspec2array("NAME=alarm.dly.*")) {
Log3 $hash,1,"[Alarm] Killing delayed action $d";
CommandDelete(undef,$d);
}
#-- replace some parts
my @evtpart = split(" ",$evt);
@ -812,7 +845,7 @@ sub Alarm_CreateNotifiers($){
}
#-- temporary code: transferm from attributes to hash
Alarm_transform($hash);
#Alarm_transform($hash);
for( my $level=0;$level<$alarmno;$level++ ){
@ -855,14 +888,24 @@ sub Alarm_CreateNotifiers($){
foreach my $d (keys %defs ) {
next if(IsIgnored($d));
if( AttrVal($d, "alarmDevice","") eq "Sensor" ) {
my @aval = split('\|',AttrVal($d, "alarmSettings",""));
my $avl = AttrVal($d, "alarmSettings","");
$avl =~ s/\\\|/%7C/g;
my @aval = split('\|',$avl);
if( int(@aval) != 4){
# Log3 $hash, 1, "[Alarm $level] Settings incomplete for sensor $d";
Log3 $hash,1, "[Alarm $level] Settings $avl incomplete for alarmSensor $d";
next;
}
if( (index($aval[0],"alarm".$level) != -1) && ($aval[3] eq "off") ){
for( my $i=0;$i<4;$i++ ){
$aval[$i] =~ s/\\//g;
$aval[$i] =~ s/%7C/\|/g;
}
#-- workaround: replace any space by \s
$aval[1] =~ s/\s/\\s/g;
if( (index($aval[0],"alarm".$level) != -1) && ($aval[1] ne "") && ($aval[3] eq "off")){
$cmd .= '('.$aval[1].')|';
#Log3 $hash,1,"[Alarm $level] Adding sensor $d to cancel notifier";
Log3 $hash,5,"[Alarm $level] Adding sensor $d to cancel notifier";
}
}
}
@ -875,7 +918,7 @@ sub Alarm_CreateNotifiers($){
CommandDefine(undef,$cmd);
CommandAttr (undef,'alarm'.$level.'.off.N room '.$alarmpublicroom);
CommandAttr (undef,'alarm'.$level.'.off.N group alarmNotifier');
Log3 $hash,5,"[Alarm $level] Created cancel notifier";
Log3 $hash,3,"[Alarm $level] Created cancel notifier";
#-- now set up the command for raising alarm - only if cancel exists
$cmd = '';
@ -884,19 +927,20 @@ sub Alarm_CreateNotifiers($){
foreach my $d (sort keys %defs ) {
next if(IsIgnored($d));
if( AttrVal($d, "alarmDevice","") eq "Sensor" ) {
my @aval = split('\|',AttrVal($d, "alarmSettings",""));
my $avl = AttrVal($d, "alarmSettings","");
my @aval = split('\|',$avl);
if( int(@aval) != 4){
Log3 $hash, 5, "[Alarm $level] Settings incomplete for alarmSensor $d";
Log3 $hash, 1, "[Alarm $level] Settings $avl incomplete for alarmSensor $d";
next;
}
if( index($aval[0],"alarm".$level) != -1){
if( $aval[3] eq "on" ){
if( ($aval[1] ne "") && ($aval[3] eq "on") ){
$cmd .= '('.$aval[1].')|';
Log3 $hash,5,"[Alarm $level] Adding alarmSensor $d to raise notifier";
}elsif( $aval[3] eq "arm" ){
}elsif( ($aval[1] ne "") && ($aval[3] eq "arm") ){
$cmdarm .= '('.$aval[1].')|';
Log3 $hash,5,"[Alarm $level] Adding alarmSensor $d to arm notifier";
}elsif( $aval[3] eq "disarm" ){
}elsif( ($aval[1] ne "") && ($aval[3] eq "disarm") ){
$cmddisarm .= '('.$aval[1].')|';
Log3 $hash,5,"[Alarm $level] Adding alarmSensor $d to disarm notifier";
}
@ -905,6 +949,8 @@ sub Alarm_CreateNotifiers($){
}
#-- raise notifier
if( $cmd eq '' ){
CommandAttr(undef,$name.' level'.$level.'onact 1');
CommandAttr(undef,$name.' level'.$level.'offact 1');
Log3 $hash,1,"[Alarm $level] No \"Raise\" device defined";
} else {
$cmd = substr($cmd,0,length($cmd)-1);
@ -913,7 +959,7 @@ sub Alarm_CreateNotifiers($){
CommandDefine(undef,$cmd);
CommandAttr (undef,'alarm'.$level.'.on.N room '.$alarmpublicroom);
CommandAttr (undef,'alarm'.$level.'.on.N group alarmNotifier');
Log3 $hash,5,"[Alarm $level] Created raise notifier";
Log3 $hash,3,"[Alarm $level] Created raise notifier";
#-- now set up the list of actors
$cmd = '';
@ -924,12 +970,12 @@ sub Alarm_CreateNotifiers($){
if( AttrVal($d, "alarmDevice","") eq "Actor" ) {
my @aval = Alarm_getsettings($hash,$d,"Actor");
if( int(@aval) != 4){
Log3 $hash, 5, "[Alarm $level] Settings incomplete for alarmActor $d";
Log3 $hash, 3, "[Alarm $level] Settings incomplete for alarmActor $d";
next;
}
if( index($aval[0],"alarm".$level) != -1 ){
#-- activate without delay
if(( $aval[3] eq "" )||($aval[3] eq "00:00")){
if(( $aval[3] eq "" )||($aval[3] =~ /(00:)?0?0:00/)){
$cmd .= $aval[1].';';
#-- activate with delay
} else {
@ -955,6 +1001,8 @@ sub Alarm_CreateNotifiers($){
CommandAttr(undef,$name.' level'.$level.'offact '.$cmd2);
Log3 $hash,5,"[Alarm $level] Added on/off actors to $name";
} else {
CommandAttr(undef,$name.' level'.$level.'onact 1');
CommandAttr(undef,$name.' level'.$level.'offact 1');
Log3 $hash,5,"[Alarm $level] Adding on/off actors not possible";
}
#-- arm notifier - optional, but only in case the alarm may be raised
@ -1084,7 +1132,7 @@ sub Alarm_widget($){
}
}
Log 1,"[Alarm_widget] name=$name gstate=$gstate dstate=$dstate sizep=$sizep";
Log 5,"[Alarm_widget] name=$name gstate=$gstate dstate=$dstate sizep=$sizep";
$name =~ s/'//g;
my @size=split('x',($sizep ? $sizep : '60x80'));
@ -1308,7 +1356,6 @@ sub Alarm_Html($)
$mval = ""
if( $mval eq "1");
my $xval = AttrVal($name, "level".$k."xec", 0);
my $xval = $hash->{DATA}{"armstate"}{"level".$k};
$ret .= sprintf("<tr class=\"%s\"><td class=\"col1\">".$alarm_tt->{"alarm"}." $k</td>\n", ($row&1)?"odd":"even");
$ret .= "<td class=\"col2\"><input type=\"text\" id=\"l".$k."s\" size=\"4\" maxlength=\"120\" value=\"$sval\"/>&nbsp;&nbsp;&nbsp;".
@ -1329,10 +1376,13 @@ sub Alarm_Html($)
foreach my $d (sort keys %defs ) {
next if(IsIgnored($d));
if( AttrVal($d, "alarmDevice","") eq "Sensor" ) {
my @aval = split('\|',AttrVal($d, "alarmSettings",""));
my $avl = AttrVal($d, "alarmSettings","");
#-- no escaping necessary
my @aval = split('\|',$avl);
if( int(@aval) != 4){
Log3 $hash, 1, "[Alarm] Settings incomplete for alarmSensor $d";
}
$row++;
$ret .= sprintf("<tr class=\"%s\" informId=\"$d\" name=\"sensor\">", ($row&1)?"odd":"even");
$ret .= "<td width=\"120\" class=\"col1\"><a href=\"$FW_ME?detail=$d\">$d</a></td>\n";
@ -1366,6 +1416,10 @@ sub Alarm_Html($)
next if(IsIgnored($d));
if( AttrVal($d, "alarmDevice","") eq "Actor" ) {
my @aval = Alarm_getsettings($hash,$d,"Actor");
#-- escaping before HTML publish
$aval[1] = Alarm_escape($aval[1],"beforehtml");
$aval[2] = Alarm_escape($aval[2],"beforehtml");
$aval[3] = Alarm_escape($aval[3],"beforehtml");
$row++;
$ret .= sprintf("<tr class=\"%s\" informId=\"$d\" name=\"actor\">", ($row&1)?"odd":"even");
$ret .= "<td width=\"120\" class=\"col1\"><a href=\"$FW_ME?detail=$d\">$d</a></td>\n";

View File

@ -1,15 +1,34 @@
//########################################################################################
// alarm.js
// Version 3.1
// Version 4.0
// See 95_Alarm for licensing
//########################################################################################
//# Prof. Dr. Peter A. Henning
//------------------------------------------------------------------------------------------------------
// Determine csrfToken
//------------------------------------------------------------------------------------------------------
var req = new XMLHttpRequest();
req.open('GET', document.location, false);
req.send(null);
var csrfToken = req.getResponseHeader('X-FHEM-csrfToken');
//------------------------------------------------------------------------------------------------------
// encode Parameters for URL
//------------------------------------------------------------------------------------------------------
function encodeParm(oldval) {
var newval;
newval = oldval.replace(/\+/g, '%2B');
newval = oldval.replace(/"/g, '%27');
newval = newval.replace(/#/g, '%23');
newval = newval.replace(/"/g, '%27');
newval = newval.replace(/\+/g, '%2B');
newval = newval.replace(/&/g, '%26');
newval = newval.replace(/'/g, '%27');
newval = newval.replace(/=/g, '%3D');
newval = newval.replace(/\?/g, '%3F');
newval = newval.replace(/\|/g, '%7C');
newval = newval.replace(/\s/g, '%20');
return newval;
}
@ -157,7 +176,7 @@ function alarm_setAttribute(name, attr, val) {
location = location.substr(0, location.length -1);
}
var url = document.location.protocol + "//" + document.location.host + location;
FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' ' + encodeParm(attr) + ' ' + encodeParm(val));
FW_cmd(url + '?XHR=1&fwcsrf=' + csrfToken + '&cmd.' + name + '=attr%20' + name + '%20' + encodeParm(attr) + '%20' + encodeParm(val));
}
function alarm_cancel(name, level) {
@ -170,7 +189,7 @@ function alarm_cancel(name, level) {
}
var url = document.location.protocol + "//" + document.location.host + location;
FW_cmd(url + '?XHR=1&cmd.' + name + '={Alarm_Exec("' + name + '",' + level + ',"web","button","off")}');
FW_cmd(url + '?XHR=1&fwcsrf=' + csrfToken + '&cmd.' + name + '={Alarm_Exec("' + name + '",' + level + ',"web","button","off")}');
}
function alarm_arm(name, level) {
@ -188,7 +207,7 @@ function alarm_arm(name, level) {
}
var url = document.location.protocol + "//" + document.location.host + location;
FW_cmd(url + '?XHR=1&cmd.' + name + '={Alarm_Arm("' + name + '",' + level + ',"web","button","' + command + '")}');
FW_cmd(url + '?XHR=1&fwcsrf=' + csrfToken + '&cmd.' + name + '={Alarm_Arm("' + name + '",' + level + ',"web","button","' + command + '")}');
}
function alarm_testaction(name, dev, type) {
@ -211,7 +230,7 @@ function alarm_testaction(name, dev, type) {
}
var url = document.location.protocol + "//" + document.location.host + location;
FW_cmd(url + '?XHR=1&cmd.' + name + '={Alarm_Test("' + name + '","' + cmds + '")}');
FW_cmd(url + '?XHR=1&fwcsrf=' + csrfToken + '&cmd.' + name + '={Alarm_Test("' + name + '","' + cmds + '")}');
}
@ -226,29 +245,26 @@ function alarm_set(name) {
var url = document.location.protocol + "//" + document.location.host + location;
// saving arm data
FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' armdelay ' + document.getElementById('armdelay').value);
FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' armwait ' + encodeParm(document.getElementById('armwait').value));
FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' armact ' + encodeParm(document.getElementById('armaction').value));
FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' disarmact ' + encodeParm(document.getElementById('disarmaction').value));
FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' cancelact ' + encodeParm(document.getElementById('cancelaction').value));
FW_cmd(url + '?XHR=1&fwcsrf=' + csrfToken + '&cmd.' + name + '=attr%20' + name + '%20armdelay%20' + document.getElementById('armdelay').value);
FW_cmd(url + '?XHR=1&fwcsrf=' + csrfToken + '&cmd.' + name + '=attr%20' + name + '%20armwait%20' + encodeParm(document.getElementById('armwait').value));
FW_cmd(url + '?XHR=1&fwcsrf=' + csrfToken + '&cmd.' + name + '=attr%20 ' + name + '%20armact%20' + encodeParm(document.getElementById('armaction').value));
FW_cmd(url + '?XHR=1&fwcsrf=' + csrfToken + '&cmd.' + name + '=attr%20' + name + '%20disarmact%20' + encodeParm(document.getElementById('disarmaction').value));
FW_cmd(url + '?XHR=1&fwcsrf=' + csrfToken + '&cmd.' + name + '=attr%20' + name + '%20cancelact%20' + encodeParm(document.getElementById('cancelaction').value));
// saving start and end times
for (var i = 0;
i < alarmno;
i++) {
FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' level' + i + 'start ' + document.getElementById('l' + i + 's').value);
FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' level' + i + 'end ' + document.getElementById('l' + i + 'e').value);
FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' level' + i + 'msg ' + document.getElementById('l' + i + 'm').value);
FW_cmd(url + '?XHR=1&fwcsrf=' + csrfToken + '&cmd.' + name + '=attr%20' + name + '%20level' + i + 'start%20' + document.getElementById('l' + i + 's').value);
FW_cmd(url + '?XHR=1&fwcsrf=' + csrfToken + '&cmd.' + name + '=attr%20' + name + '%20level' + i + 'end%20' + document.getElementById('l' + i + 'e').value);
FW_cmd(url + '?XHR=1&fwcsrf=' + csrfToken + '&cmd.' + name + '=attr%20' + name + '%20level' + i + 'msg%20' + document.getElementById('l' + i + 'm').value);
if (document.getElementById('l' + i + 'x').checked == true) {
val = "armed";
} else {
val = "disarmed";
}
FW_cmd(url + '?XHR=1&cmd.' + name + '=attr ' + name + ' level' + i + 'xec ' + val);
FW_cmd(url + '?XHR=1&fwcsrf=' + csrfToken + '&cmd.' + name + '=attr%20' + name + '%20level' + i + 'xec%20' + val);
}
//for (var k in ah.items) {
// ah.setItem(k,document.getElementById(k).value);
//}
// acquiring data for each sensor
var sarr = document.getElementsByName('sensor');
@ -264,12 +280,11 @@ function alarm_set(name) {
val += "alarm" + i + ",";
}
}
val += "|" + sarr[k].children[2].children[0].value;
val += "|" + sarr[k].children[3].children[0].value;
val += "|" + encodeParm(sarr[k].children[2].children[0].value);
val += "|" + encodeParm(sarr[k].children[3].children[0].value);
val += "|" + sarr[k].children[4].children[0].options[sarr[k].children[4].children[0].selectedIndex].value;
FW_cmd(url + '?XHR=1&cmd.' + nam + '=attr ' + nam + ' alarmSettings ' + encodeParm(val));
FW_cmd(url + '?XHR=1&fwcsrf=' + csrfToken + '&cmd.' + nam + '=attr%20' + nam + '%20alarmSettings%20' + val);
}
// acquiring data for each actor
var aarr = document.getElementsByName('actor');
for (var k = 0;
@ -285,12 +300,12 @@ function alarm_set(name) {
val += "alarm" + i + ",";
}
}
val += "|" + aarr[k].children[2].children[0].value;
val += "|" + aarr[k].children[3].children[0].value;
val += "|" + aarr[k].children[4].children[0].value;
FW_cmd(url + '?XHR=1&cmd.' + nam + '=attr ' + nam + ' alarmSettings ' + encodeParm(val));
val += "|" + encodeParm(aarr[k].children[2].children[0].value);
val += "|" + encodeParm(aarr[k].children[3].children[0].value);
val += "|" + encodeParm(aarr[k].children[4].children[0].value);
FW_cmd(url + '?XHR=1&fwcsrf=' + csrfToken + '&cmd.' + nam + '=attr%20' + nam + '%20alarmSettings%20' + val);
}
// creating notifiers
FW_cmd(url + '?XHR=1&cmd.' + name + ' ={main::Alarm_CreateNotifiers("' + name + '")}');
FW_cmd(url + '?XHR=1&fwcsrf=' + csrfToken + '&cmd.' + name + ' ={main::Alarm_CreateNotifiers("' + name + '")}');
}