Saunasteuerung: HttpUtils_NonblockingGet und Cookie mitsenden

Begonnen von xasher, 22 April 2022, 08:56:59

Vorheriges Thema - Nächstes Thema

xasher

Hallo zusammen,

ich bin gerade am entwickeln eines Moduls. Gerade bin ich mit Teil 1 fertig. Ich kann die Sauna mittels curl steuern (Annschalten, Ausschalten, Werte wie Temperatur ändern). Dazu hatte ich auch Unterstützung von einem Entwickler von digitalstrom.

Ich hänge gerade bei der Einschaltprozedur. Die läuft im Wesentlichen in 3 Schritten ab:

1) Login und ".ASPXAUTH" Cookie erhalten
2) Get Anfrage mit der SaunaI auf eine URL um ein Antiforgery Cookie zu erhalten (__RequestVerificationToken). Dazu muss das ".ASPXAUTH" Cookie mitgesendet werden.
3) POST Anfrage mit __RequestVerificationToken, PIN (zuvor an der Saunasteuerung festgelegt) und SaunaID

Dann springt die Sauna an. Die Änderung der Werte ist dann über json.

Schritt 1 habe ich zum Test erstmal so (hart)codiert:

   
    my $header = "Content-Type: application/x-www-form-urlencoded";
    my $datauser   = 'UserName=user&Password=geheim;

    HttpUtils_NonblockingGet({
        url        => AUTHURL,
        ignoreredirects => 1,
        timeout    => 5,
        hash        => $hash,
        method      => "POST",
        header      => $header, 
data => $datauser,
        callback    => \&Klafs_APIAuthResponse,
    }); 
   
}
sub Klafs_APIAuthResponse($) {
    my ($param, $err, $data) = @_;
    my $hash = $param->{hash};
    my $name = $hash->{NAME};
    Log3 $name, 2, "-----------------------------------------------";
    Log3 $name, 2, "COOKIE: $data";
    Log3 $name, 2, "-----------------------------------------------";
    Log3 $name, 2, "-----------------------------------------------";
    Log3 $name, 2, "err: $err";
    Log3 $name, 2, "-----------------------------------------------";
    Log3 $name, 2, "-----------------------------------------------";
    Log3 $name, 2, "header:" . $param->{httpheader};
    Log3 $name, 2, "-----------------------------------------------";
    my $header = $param->{httpheader};
   
    foreach my $cookie ($header =~ m/set-cookie: ?(.*)/gi) {
        Log3 $name, 2, "$name: GetCookies found Set-Cookie: $cookie";
        $cookie =~ /([^,; ]+)=([^,;\s\v]+)[;,\s\v]*([^\v]*)/;
        Log3 $name, 4, "$name: GetCookies parsed Cookie: $1 Wert $2 Rest $3";
        my $name  = $1;
        my $value = $2;
        my $rest  = ($3 ? $3 : "");
        my $path  = "";
        if ($rest =~ /path=([^;,]+)/) {
            $path = $1;
        }
        my $key = $name . ';' . $path;
        $hash->{HTTPCookieHash}{$key}{Name}    = $name;
        $hash->{HTTPCookieHash}{$key}{Value}   = $value;
        $hash->{HTTPCookieHash}{$key}{Options} = $rest;
        $hash->{HTTPCookieHash}{$key}{Path}    = $path;
       
# set Readings
readingsBeginUpdate($hash);
readingsBulkUpdate($hash,'cookie_name',$hash->{HTTPCookieHash}{$key}{Name} );
readingsBulkUpdate($hash,'cookie_value',$hash->{HTTPCookieHash}{$key}{Value} );
readingsBulkUpdate($hash,'cookie_options',$hash->{HTTPCookieHash}{$key}{Options} );
readingsBulkUpdate($hash,'cookie_path',$hash->{HTTPCookieHash}{$key}{Path} );
readingsEndUpdate($hash, 1);
   }
}

Die Antwort wird ausgewertet - mit viel debugging und in ein Reading geschrieben. Also das ASPXAUTH.

Jetzt bei Anfrage 2 scheitere ich. Wo gebe ich da das ASPXAUTH mit? Ich habs im Header versucht, aber daran gescheitert

     my $header = ".ASPXAUTH=xxxx";
     my $datauser = 's=11111-2222-3333-ffff-xxxxx';
    HttpUtils_NonblockingGet({
        url        => "https://sauna-app.klafs.com/Control/EnterPin",
        timeout    => 5,
        hash        => $hash,
        method      => "GET",
        header      => $header, 
data => $datauser,
        callback    => \&Klafs_GETantiforgery,
    }); 
   
     # RequestVerificationToken  aus dem Header auslesen für das Cookie
     sub Klafs_GETantiforgery($) {
       my ($param, $err, $data) = @_;
       my $hash = $param->{hash};
       my $name = $hash->{NAME};
       Log3 $name, 2, "COOKIE: $data";
       Log3 $name, 2, "err: $err";
       Log3 $name, 2, "header:" . $param->{httpheader};
     }


Hier noch der Auszug von den Kollegen von digitalstrom in c

int klafs_power_on() {
vdc_report(LOG_NOTICE, "network: Power on sauna\n");

struct memory_struct *response = NULL;

char request_body[1024];
strcpy(request_body, "s=");
strcat(request_body, klafs.sauna.id);

response = http_post(url_enterpin, request_body, NULL, klafs.aspxauth); if (response == NULL) { vdc_report(LOG_ERR, "network: getting sauna values failed\n"); return KLAFS_GETREQVERIFYTOKEN_FAILED; } extractRequestVerificationToken(response->memory);
char request_body2[1024];
strcpy(request_body2, "__RequestVerificationToken="); strcat(request_body2, klafs.verificationtoken); strcat(request_body2, "&Pin="); strcat(request_body2, klafs.pin); strcat(request_body2, "&saunaId="); strcat(request_body2, klafs.sauna.id);

response = http_post(url_enterpin, request_body2, NULL, klafs.aspxauth);

if (response == NULL) {
vdc_report(LOG_ERR, "network: power on sauna failed\n"); return KLAFS_CONNECT_FAILED; }

if (strstr(response->memory,"security check") != NULL || strstr(response->memory,"Sicherheitskontrolle") != NULL) { vdc_report(LOG_NOTICE, "security control for sauna not done; cannot power on remotely!\n"); return -1; }

free(response->memory);
free(response);

//get latest sauna values and do a immediate push to DSS; in case power on failed, e.g. security check not done in sauna, isPoweredOn stays "false"
klafs_get_values();
push_binary_input_states();

return 0;
}


Da wird das cookie in Position 4 bei http_post mitgegeben. Gibts so etwas auch bei HttpUtils_NonblockingGet ?

Vielen Dank schon mal für Ideen

Grüße,
Alex

rudolfkoenig

ZitatDa wird das cookie in Position 4 bei http_post mitgegeben. Gibts so etwas auch bei HttpUtils_NonblockingGet ?
Cookies werden als HTTP Header versendet, siehe https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies.
Der header Parameter in HttpUtils_NonblockingGet ist entweder ein String (mit \r\n als Trenner, aber nicht am Ende):

header => "Content-Type: application/x-www-form-urlencoded\r\n".
          "Cookie: ASPXAUTH=bla; yummy_cookie=choco; tasty_cookie=strawberry",

oder ein Objekt:

header => { "Content-Type" => "application/x-www-form-urlencoded",
            "Cookie" => "ASPXAUTH=bla; yummy_cookie=choco; tasty_cookie=strawberry" },


xasher

Hallo Rudolf,

Mensch, vielen Dank. Es lag tatsächlich am Syntax "cookie: ....". Das hatte ich nicht vorneangestellt.
Jetzt geht die Sauna an. Prima, so kann ich jetzt arbeiten.

Dankeschön!!!!

Grüße
Alex