Es bleibt nur uneingeschränktes Misstrauen

https://www.heise.de/news/Nur-NIST-P-521-betroffen-PuTTY-Luecke-kompromittiert-private-SSH-Schluessel-9687539.html

Der freie Terminal-Client PuTTY trug seit Version 0.68 – veröffentlicht im Jahr 2017 – einen Programmierfehler mit sich herum, der Angreifern die Rekonstruktion privater SSH-Schlüssel des Typs NIST P-521 ermöglicht. Dafür müssen sie jedoch entweder ihr Opfer auf einen präparierten SSH-Server locken oder vom betroffenen Schlüssel signierte Git-Commits abfangen. Bei NIST P-521 handelt es sich um ein Verfahren der Kryptografie auf elliptischen Kurven (Elliptic Curve Cryptography, ECC).

Seit 7 Jahren, soso. Und auch noch mit elliptischen Kurven, die doch besonders sicher sein sollen.

In einem (äußerst sehenswerten!) Interview bei Tucker Carlson Network sagte Pavel Durov, Gründer der Social-Media-Plattform Telegram, kürzlich, er betrachte absolut jedes technische Gerät, mit dem er in Berührung kommt, als kompromittiert. Und nun, wenn man sich die abenteuerliche Flut von Lücken und Fehlern ansieht, die täglich in unüberschaubarer Zahl auf uns einprasseln, wird er damit wohl leider recht haben.

img2pdf Bild Konverter

Vielleicht kennen Sie das Problem: Sie haben eine Bilddatei, benötigen diese jedoch als PDF. In unserer Buchhaltung kommt das öfters vor, ein Photo, oder aus einer Banking-Software heraus. Aber das Steuerbüro akzeptiert nur PDF. Also muss das Image nach PDF konvertiert werden. Das ist natürlich gar kein Problem, beherrscht inzwischen jedes Betriebssystem. Doch vielleicht möchten Sie den Prozess automatisieren? Oder die Klicks reduzieren, um den PDF-Konverter aus der Anwendungssoftware heraus anzustoßen?

Hier ist ein kleines Tool für Bash, das eine riesige Auswahl von Bildformaten nach PDF konvertieren kann:

########################################################
# img2pdf.bash - Convert many image formats to PDF     #
# More info https://cephei.blog/img2pdf-bild-konverter #
########################################################
#!/bin/bash

delete_original=0
dpi=300
format="DINA4"
plain=0
auto_orient=""
verbose=0

usage() {
    echo "Usage: $(basename $0) [-d] [-i ] [-f ] [-p] [-v] file1 [file2 ...]"
    echo "   -d Delete file after conversion"
    echo "   -i  DPI value [300] for the converted PDF"
    echo "   -f  [DINA4], DINA3, DINA5, LETTER"
    echo "   -p Plain, do not scale image"
    echo "   -o Keep orientation (portrait/landscape)"
    echo "   -v Verbose, inform about progress"
    exit 1
}

verbose_echo() {
    if [ "$verbose" -eq 1 ]; then echo "$@"; fi
}

supported_file() {
    if [ ! -f "$1" ]; then return 1; fi
    if [ -n  "$(file "$1" |grep PDF)" ]; then return 1; fi
    if ! magick identify "$1" &>/dev/null; then return 1; fi
    return 0
}

# Check for required commands
if ! command -v convert &>/dev/null || ! command -v magick &>/dev/null || ! command -v bc &>/dev/null; then
    echo "ImageMagick not installed. Please install ImageMagick to use this script."
    echo "Hint: on most distributions, this package is named \"imagemagick\"."
    echo "(Should this appear although ImageMagick is installed, your distro misses \"bc\")"
    exit 1
fi

if [ "$#" -eq 0 ]; then usage; fi

while getopts ":di:f:pov" opt; do
    case $opt in
        d) delete_original=1 ;;
        i) dpi=$OPTARG ;;
        f) format=$(echo "$OPTARG" | tr '[:lower:]' '[:upper:]') ;; #ignore case
        p) plain=1 ;;
        o) auto_orient="-auto-orient" ;;
        v) verbose=1 ;;
        \?) echo "Invalid option: -$OPTARG" >&2
            usage
            ;;
        :) echo "Option -$OPTARG requires an argument." >&2
           usage
           ;;
    esac
done

shift $((OPTIND-1))
if [ "$#" -eq 0 ]; then usage; fi

if [ $plain -eq 0 ]; then
    # Configure settings based on format and DPI, reference values for 300 DPI
    case "$format" in
        DINA4) xsiz=2480; ysiz=3508 ;;
        DINA3) xsiz=3508; ysiz=4961 ;;
        DINA5) xsiz=1748; ysiz=2480 ;;
        DINA6) xsiz=1240; ysiz=1748 ;;
        LETTER) xsiz=2550; ysiz=3300 ;;
        *) echo "Unsupported format: $format" >&2
        exit 1 ;;
    esac
    
    scale_factor=$(echo "scale=8; 300 / $dpi" | bc)
    xsiz=$(echo "($xsiz / $scale_factor + 0.5) / 1" | bc) # Note: "/ 1" simulates floor
    ysiz=$(echo "($ysiz / $scale_factor + 0.5) / 1" | bc)
    verbose_echo "Conversion settings: DPI=$dpi, Format=$format, Scale Factor=$scale_factor"
else
    verbose_echo "[plain] was set on command line, image(s) are not scaled"
fi

for file in "$@"; do
    if supported_file "$file"; then
        output_file="${file%.*}.pdf"
  
        if [ $plain -eq 0 ]; then      
            convert "$file" $auto_orient -resize "${xsiz}x${ysiz}" -gravity center -extent ${xsiz}x${ysiz} -units PixelsPerInch -density $dpi "$output_file"
        else
            convert "$file" "$output_file"
        fi
        verbose_echo "Converted: $file -> $output_file"
        
        if [ $delete_original -eq 1 ]; then
            rm "$file"
            verbose_echo "Deleted: $file"
        fi
    else
        echo "Ignored: $file is either not a supported image format or does not exist." >&2
    fi
done

Alle von ImageMagick unterstützten Bildformate können mit diesem Script nach PDF konvertiert werden, und das ist eine schier unüberschaubare Anzahl von Formaten. Falls ImageMagick auf Ihrem System nicht verfügbar ist, das zugehörige Paket heißt „imagemagick“ unter Debian, Fedora und Arch.

Um unser Script zu installieren, kopieren Sie es entweder aus dem Code-Fenster oberhalb, oder Sie laden ein ZIP von unserem Server. img2pdf ist Freeware und Sie dürfen es nach Belieben verwenden.

Hinweis: Bei einzelnen Abschnitten des Codes wurde auf die Unterstützung von ChatGPT zurückgegriffen, aber OpenAI erhebt keinerlei Copyright-Ansprüche auf solche Code-Anteile.

WLAN situativ einschalten

Vielleicht kennen Sie das Problem. Sie haben ein Notebook und nutzen es stationär und mobil. Wenn Sie das Notebook stationär nutzen, verwenden Sie den Ethernet-Anschluss, aber für den mobilen Einsatz benötigen Sie das WLAN. Also können Sie das WLAN nicht dauerhaft deaktivieren, aber wenn das Notebook über Ethernet verbunden ist, ist das WLAN überflüssig, unter Umständen störend (weil Sie zwei Verbindungen zum Router aufbauen und eine davon, nämlich das WLAN, deutlich langsamer ist als die andere, und es sich nicht genau sagen lässt, über welche der beiden aktiven Verbindungen Datenverkehr geleitet wird), und außerdem möchten Sie vielleicht Ihre Strahlenexposition minimieren, wenn das Notebook stationär verwendet wird. Da wäre es doch geschickt, wenn das System selbst entscheiden könnte, ob WLAN gerade gebraucht wird oder nicht. Hier ist ein mit Unterstützung von ChatGPT erstelltes Script, das diese Aufgabe in hinreichend modernen Linux-Distributionen (SystemD) mit dem bash-Interpreter erfüllt:

#!/bin/bash

# Ermittle die Gerätenamen für WLAN und Ethernet
WIFI="$(nmcli device status | grep "wifi " | awk '{print $1}')"
ETHN="$(nmcli device status | grep "ethernet " | awk '{print $1}')"

if [[ -z "$WIFI" || -z "$ETHN" ]]; then
    echo "Zuordnung der Netzwerk-Adapter fehlgeschlagen."
    exit 1
fi

# nmcli gibt den Status in der GENERAL.STATE-Spalte aus
# 20 entspricht 'nicht verbunden', 100 bedeutet 'verbunden'
wifiStatus="$(nmcli -g GENERAL.STATE device show $WIFI)"
ethnStatus="$(nmcli -g GENERAL.STATE device show $ETHN)"

# Prüfen, ob Ethernet verbunden ist (Status 100)
if [[ ! "$ethnStatus" =~ 100 ]]; then
    # Ethernet ist nicht verbunden
    if [[ "$wifiStatus" =~ 20 ]]; then
        # WLAN ist deaktiviert, schalte es ein
        nmcli radio wifi on
    fi
else
    # Ethernet ist verbunden
    if [[ ! "$wifiStatus" =~ 20 ]]; then
        # WLAN ist nicht deaktiviert, schalte es aus
        nmcli radio wifi off
    fi
fi

Das Script benötigt keine Admin-Rechte und kann im regulären User-Startup eingebunden werden.

PS: Der Operator „=~“ wird im Script als sozusagen infix-Suche verwendet. Die Ausgabe von nmcli ist nämlich „100 (verbunden)“ oder auch „100 (connected)“, bzw. abhängig von der eingestellten Sprache des Betriebssytems.

Ergänzung: Das Script funktioniert nur, wenn nur ein Ethernet- und nur ein WLAN-Adapter im System vorhanden sind. Falls Sie mehrere Adapter haben, müssten Sie das Script entsprechend anpassen. Um z.B. nur das jeweils erste Device zu verwenden:

WIFI="$(nmcli device status | grep "wifi " | head -1 | awk '{print $1}')"
ETHN="$(nmcli device status | grep "ethernet " | head -1 | awk '{print $1}')"

beziehungsweise wie es für Ihr System passend ist.

Organisierte Verantwortungslosigkeit

https://www.danisch.de/blog/2024/02/10/technische-fehler-beim-abruf-von-e-rezepten-erhebliche-gefaehrdung-der-arzneimitteltherapiesicherheit-moeglich/

Beim E-Rezept sind gravierende Fehler aufgetreten, die zu schwerwiegenden Gesundheitsgefährdungen führen können. Beim Auslesen der Verordnungen von der Gesundheitskarte in Apotheken wurden Medikamente vertauscht.

Ein Apotheker schlägt bei Hadmut Danisch Alarm. Mit dem E-Rezept kommt es zu gravierenden Vertauschungen mit potenziell tödlichen Auswirkungen. Man sollte also bei E-Rezepten sehr genau prüfen, welches Medikament der Apotheker über die Theke reicht und sowieso immer den Beipackzettel ausführlich studieren.

Nun ja. Es ist, wie es eigentlich immer ist. Computer und IT können sehr segensreiche und hilfreiche Erweiterungen der menschlichen Fähigkeiten sein, aber, so wie sich das manche vorstellen, den Menschen ersetzen können sie nicht. Das liegt schon einmal allein daran, dass Menschen ein Bewusstsein dafür haben, dass sie Fehler machen können, Computer aber nicht. Computer machen ja eigentlich auch gar keine Fehler, sie machen nur das, was Menschen ihnen programmiert haben. Und Menschen machen eben Fehler. Aber sobald etwas durch einen Computer geht, neigen wir dazu, es als „göttlichen Ratschluss“ aufzufassen. Vielleicht aber ist es auch so, niemand ist mehr schuld, sobald der Computer es gesagt hat, sprich, der Kinderglaube an eine allein Nutzen stiftende Technisierung der Gesellschaft ist eigentlich nur ein Rückzug aus der Veranwortung.

Übrigens hat der Apotheker ein offizielles Schreiben des Sächsischen Apothekenverbandes beigefügt, das aber so strikt auf Vertraulichkeit pocht, dass Danisch sich nicht traut, daraus zu zitieren, geschweige denn, es zu veröffentlichen. Das ist ja wieder mal bezeichnend, dass wir so etwas nicht wissen sollen. Ist ja bloß unser (physisches!) Leben, um das es hier geht, solcher „Kleinkram“ darf doch die Gewinne der Konzerne und den Überwachungs- und Kontrollwahn der zunehmend ins Totalitäre abgleitenden Politik nicht gefährden.

Arrogant oder überfordert?

https://zolutal.github.io/aslrnt/

As it turns out, on recent Ubuntu, Arch, Fedora, and likely other distro’s releases, with kernel versions >=5.18, library ASLR is literally broken for 32-bit libraries of at least 2MB in size, on certain filesystems. Also, ASLR’s entropy on 64-bit libraries that are at least 2MB is significantly reduced, 28 bits -> 19 bits, on certain filesystems.

Seit 1½ Jahren ist ASLR (Address Space Layout Randomization, wichtige Technik um die Vorhersagbarkeit von Einsprungadressen zu erschweren) in so ziemlich jedem modernen Linux kaputt. Hier ist der Link zum Bug-Tracker. Ist es diese Einstellung „Linux greift eh niemand an, weil es so wenige benutzen“? Oder ist die Linux-Foundation mit der enormen Komplexität, die Linux mittlerweile erreicht hat, schlicht überfordert? Dass so etwas passieren kann, mag ja unvermeidlich sein, aber dass ein derart essentielles Sicherheitsproblem 1½ Jahre vor sich hinschnarcht, ist maximales Versagen.

Kinderkrankheiten oder Totgeburt?

https://www.visualcapitalist.com/sp/9-problems-with-generative-ai-in-one-chart/

In the rapidly evolving landscape of artificial intelligence, generative AI tools are demonstrating incredible potential. However, their potential for harm is also becoming more and more apparent. Together with our partner VERSES, we have visualized some concerns regarding generative AI tools using data from a variety of different sources.

Da der erste KI-Hype abgeklungen ist, richtet sich der Blick verstärkt auf die mannigfaltigen Probleme, die diese neue Technologie mit sich bringt. Dieser Artikel von „Visual Capitalist“ bietet eine recht gute Übersicht. Eine deutsche Übersetzung finden Sie hier.

Fedora 39 veröffentlicht

https://www.phoronix.com/news/Fedora-39-Released

While delayed by several weeks compared to their initial release goals, today marks the availability of Fedora 39 as a wonderful upgrade to this popular Linux distribution.

Fedora, die Linux-Distribution, welche Linus Torvalds verwendet, hat heute das Upgrade zu Version 39 freigegeben. Sollte es Ihnen nicht angezeigt werden, lesen Sie bitte diesen Artikel in unserem Blog.

Übrigens, falls Sie als Umsteiger aus der Windows-Welt sich nicht so recht mit GNOME und KDE anfreunden können, wussten Sie schon, dass es eine Cinnamon-Variante von Fedora gibt? Cinnamon ist der wohl umsteigerfreundlichste Desktop, und natürlich kann man ihn auf jeder Variante von Fedora nachinstallieren. Aber es ist immer besser, wenn der gewünschte Desktop bereits in der Installation nativ integriert ist. Hier ist der Link zur Cinnamon-Variante von Fedora.

80.000 Zeilen blanker Terror

https://www.phoronix.com/news/XOrg-Vulnerabilities-Since-1988

Made public today was CVE-2023-43785 as an out-of-bounds memory access within the libX11 code that has been around since 1996. A second libX11 flaw is stack exhaustion from infinite recursion within the PutSubImage() function of libX11… This vulnerability has been around since X11R2 in February of 1988. A third libX11 vulnerability made public today is an integer overflow within XCreateImage() that leads to a heap overflow… That too has been around since X11R2 in 1988.

Immer noch sehr viele Linux-Distributionen verlassen sich auf das X11 Protokoll, aber dieses ist notorisch unsicher –  “80,000 lines of sheer terror“, sagte ein Sicherheitsforscher dazu. 35 Jahre alte Fehler, die erst jetzt veröffentlicht werden! Man muss es schon sagen, die Tatsache, dass über lange Zeit Linux-Systeme mangels Verbreitung kaum angegriffen wurden, hat offenbar zu einer gewissen Laxheit in Bezug auf Sicherheitsthemen bei den Linux-Entwicklern geführt.

Abhilfe ist jedoch in Sicht, immer mehr Distributionen stellen auf Wayland um, welches das X11 Protokoll durch ein sicheres, modernes und einfacheres Protokoll ersetzt. Problematisch daran ist allenfalls, dass das dazu führen könnte, dass die Pflege von X11 noch mehr vernachlässigt wird, obwohl die Adaption von Wayland bisher recht schleppend verläuft.

Falle in Fedora

Früher gab es für die Aktualisierung von GRUB2 in Fedora zwei unterschiedliche Befehle. Für BIOS-Systeme war es:
sudo grub2-mkconfig -o /boot/grub2/grub.cfg und für EFi-Systeme:
sudo grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg.

Inzwischen hat jedoch Fedora die durchaus begrüßenswerte und vernünftige Entscheidung getroffen, für beide Systeme nur noch ein Kommando zu verwenden, nämlich das für BIOS-Systeme. Im EFI-Verzeichnis wird neuerdings nur noch auf eine  einheitliche grub.cfg gesourced, und diese tatsächliche grub.cfg liegt für beide Systeme in /boot/grub2/grub.cfg.

Daraus ergibt sich jedoch eine tückische Falle. Denn auf vielen Webseiten finden sich noch immer, so wie eingangs beschrieben, zwei verschiedene Befehle je nach System. Aber wenn man in einem neueren Fedora nur einmal den EFI-Befehl eingibt, ist der Update-Mechanismus danach kaputt. Wenn dann z.B. in dnf eine neue Kernel-Version installiert wird, wird der danach ausgeführte implizite Update für GRUB2 zwar die /boot/grub2/grub.cfg bearbeiten, aber nicht die /boot/efi/EFI/fedora/grub.cfg. Diese zweite Datei hat jedoch beim Booten in GRUB Vorrang, und deshalb wird der neue Kernel dann nicht gestartet. Und wie es mit späteren größeren Updates aussieht, z.B. Update auf eine höhere Fedora-Version, ist sowieso ungewiss.

Abhilfe ist wie folgt:

sudo rm /boot/efi/EFI/fedora/grub.cfg
sudo dnf reinstall grub2-efi-x64 shim-x64 grub2-tools
sudo dnf reinstall grub2-common
sudo grub2-mkconfig -o /boot/grub2/grub.cfg

Die EFI grub.cfg sieht danach so aus:

search --no-floppy --fs-uuid --set=dev 9baexxxx-xxxx-xxxx-xxxx-xxxxxxxxcd35
set prefix=($dev)/grub2
export $prefix
configfile $prefix/grub.cfg

und verweist  bzw. sourced auf die grub.cfg in /boot/grub2. Und danach funktioniert auch wieder der dnf-Mechanismus, z.B. in dnfdragora.

Ergänzung 13.08.2023: Es ist möglich, dass durch den fehlgegangenen efi-update-grub außerdem die Variable GRUB_ENABLE_BLSCFG in /etc/default/grub verstellt wurde. Diese Variable sollte unter Fedora auf „true“ stehen, könnte aber durch den veralteten efi-update-grub auf „false“ gegangen sein (GRUB_ENABLE_BLSCFG=false). Dies könnte wiederum mit anderen Update-Mechanismen von Fedora kollidieren und zu weiteren Problemen führen. Als Abhilfe den Wert auf „true“ setzen (GRUB_ENABLE_BLSCFG=true) und anschließend
sudo grub2-mkconfig -o /boot/grub2/grub.cfg“. Mehr Info zu diesem Problem hier: https://forums.fedoraforum.org/showthread.php?331019-Fedora-38-not-booting-with-kernel-version-gt-6-4-6

Werkzeuge für Kammerjäger

https://rieckpil.de/spring-boot-testing-best-practices/

Let’s admit the truth. Testing is often an overlooked aspect of software development and an afterthought in most teams. There are very few developers who actively enjoy writing tests. Only a few know how to write automated tests effectively. Albeit we all admit and learned that testing helps ensure that our application is robust, reliable, and works as intended, there’s not much traction in this area. In this article, we’ll look at the most common testing Spring Boot testing best practices to provide a good starting point for testing enterprise Spring Boot applications.

Sehr interessanter Überblick für die Strategien zum „Entlausen“ von Spring Boot Code. Übrigens konnte ich neulich nicht mehr drucken. Treiber neu installiert, dies das. Am Ende guckte ich dann doch mal auf den Drucker. Ich hatte es noch gehört, am Klicken der Rückmeldungen, ein winziges Insekt war über dessen Touchscreen spaziert – und hatte damit wahllos irgendwelche Funktionen angewählt, die den Drucker in einen Wartezustand (auf eine weitere Eingabe) versetzt hatten, und solange er darin war, nahm er keine Druckaufträge mehr an. Tja, es gibt sie immer noch, die echten Bugs (Käfer), genau wie damals ihren Namensgeber, dem verschmorten Insekt, das 1950 oder so einen der ersten Großrechner per Kurzschluss lahmgelegt hatte.

Sicherheit als Performance-Hindernis

https://blog.fefe.de/?ts=9a65c751

Wenn der Compiler versteht, dass OPENSSL_cleanse keine Seiteneffekte hat außer key zu überschreiben, dann ist das ein klarer Fall für die Dead Store Elimination. Ähnlich sieht es mit einem memset() vor einem free() aus. Das ist vor ein paar Jahren aufgefallen, dass Compiler das nicht nur tun können sondern sogar in der Praxis wirklich tun. Plötzlich lagen im Speicher von Programmen Keymaterial herum. Also musste eine Strategie her, wie man den Compiler dazu bringt, das memset nicht wegzuoptimieren.

Sehr spannende Analyse von Fefe, wie Optimierungen des Compilers die Sicherheit von Software untergraben können. Da gibt man sich als Programmierer alle Mühe, sensible Daten aufzuräumen, und dann schmeißt der Compiler den Code wieder raus, weil er ihn für unnötig hält. Und Abhilfe ist gar nicht so einfach.

Kein Wunder, dass immer neue Lücken gefunden werden in Betriebssystemen und Software. Die Komplexität der SW-Entwicklungs-Prozesse hat ein derartiges Ausmaß angenommen, dass sie nur noch mit sehr hohem Testaufwand beherrschbar sind. Fefes Artikel beleuchtet dabei den interessanten Aspekt, dass sogar eine neue Compiler-Version Sicherheitslücken in Code reißen könnte, der ursprünglich sicher geschrieben war. Wer würde bei Recompilation mit einer neuen Compiler-Version den erzeugten Assembler-Code neu überprüfen? Es benötigt also umfangreiche und ständige Kontrollen des Outputs, um die Stabilität der Ergebnisse des Codes auch bei der Weiterentwicklung zu gewährleisten.

Java Backend Entwickler (m/w/d)

Wir suchen zum nächstmöglichen Zeitpunkt einen

Java Backend Entwickler (Geschlecht egal)

für den Einsatz im Home-Office und beim Kunden vor Ort.

Über uns

Die Cephei AG ist ein Software-Unternehmen, das Konzerne bei der digitalen Transformation mit innovativen Konzepten und Produkten unterstützt. Wir entwickeln seit über 30 Jahren Lösungen um bestehende Geschäftsprozesse zu digitalisieren und neue digitale Geschäftsmodelle zu erschließen. Unsere Spezialgebiete sind Produktkonfiguration, Web-Portale, elektronische Beratungslösungen, mobile Apps und Telematik-Anwendungen.

Unsere Anforderungen für die ausgeschriebene Stelle

    • Universitätsabschluss im Bereich Informatik oder eine vergleichbare Ausbildung (bzw. ggfs. Nachweis der Befähigung durch bisher durchgeführte Projekte)
    • 1 – 2 Jahre Berufserfahrung min., Praktika im Studium werden berücksichtigt
    • Java
    • Spring Boot
    • Hibernate
    • SQL
    • GIT
    • REST

Nicht Bedingung, aber durchaus willkommen wären außerdem

    • Kubernetes, Docker
    • Functional Programming
    • Clean Code
    • Postgres
    • Javascript
    • Application-Security
    • Microservice Architecture

Wir berücksichtigen auch Berufseinsteiger, setzen jedoch eine gewisse Mindesterfahrung mit der SW-Entwicklung voraus. Als anerkannter Ausbildungsbetrieb (IHK) haben wir bereits mehrere Fachinformatiker ausgebildet und Erfahrung darin, Berufseinsteigern eine gute Perspektive zu bieten.

Weitere Informationen

Falls Sie für Ihre neue Stelle bei uns umziehen müssen, helfen wir Ihnen mit einem Zuschuss zu den Umzugskosten und bei der Wohnungssuche.

In unserem Team arbeiten viele langjährige Mitarbeiter. Mehr als 60% der Belegschaft sind seit mehr als 10 Jahren bei uns. Wir bieten Vertriebsprovision und Erfolgsbeteiligung und fördern aktiv Familien mit Kindern durch eine Kinderzulage sowie flexibles Zeitmanagement mit ggfs. der Möglichkeit zum Home-Office.

Unsere Mitarbeiter üben ihre Tätigkeit vorwiegend im mobilen Office aus, jedoch sind gelegentlich Arbeiten vor Ort beim Kunden erforderlich. Deshalb sollten Sie im Einzugsbereich München wohnen, oder planen, dorthin umzuziehen, wenn Sie sich bei uns bewerben möchten.

Über Ihre Bewerbung mit den üblichen Unterlagen würden wir uns sehr freuen. Bitte senden Sie Ihre Bewerbung entweder via Monster oder an bewerbung@cephei.com.

Für telefonische Rückfragen oder weitere Informationen wenden Sie sich bitte an Frau Ahrens, Tel. 089 898267-10.

Cephei AG
Herzogstr. 33
80803 München
Tel: 089 898267-0
Fax: 089 898267-22
https://www.cephei.com
bewerbung@cephei.com

Am eigenen Schopf

Neulich wollte ich einen längeren Text mit ChatGPT diskutieren. Allerdings gibt es in dessen Version 4.0 derzeit eine Prompt-Begrenzung auf 2048 Zeichen. Naja, kein Problem, dachte ich, da soll mir doch ChatGPT ein Programm dafür schreiben, und sich selbst am eigenen Schopf aus dem Gefängnis seiner Begrenzung befreien. Allerdings sollte das nicht ein simpler Split sein, sondern mit Überschriften für die einzelnen Teile und der Möglichkeit, sowohl einzelne Dateien zu erzeugen, als auch eine Gesamtdatei, die alle Teile, getrennt durch Überschriften, enthält. Außerdem sollte das Programm nach Möglichkeit nicht innerhalb einer Zeile umbrechen.

(Bestehende Tools legen einzelne Dateien ab, aber das ist ziemlich schwierig zu handhaben, wenn man die einzelnen Stücke in den Prompt einfügen will. Für so etwas ist eine Gesamtdatei mit Separatoren leichter zu bearbeiten.)

Jedenfalls, das erwies sich zunächst als gar nicht so einfach, ChatGPT servierte mir erstmal zwei Entwürfe, die beide mit oom-kills endeten (mein Rechner ging komplett in die Knie dabei, und ich habe mich schon gefragt, ob ich etwa gerade gehackt werde 😀). Dann kam aber doch eine funktionierende Version dabei heraus, die, wie ich meine, einen zwar ungewöhnlichen, aber dennoch sehr interessanten Ansatz verfolgt, um die Anforderungen zu erfüllen. Ich hatte dabei sozusagen die Rolle des Projektleiters, diktierte meine Anforderungen an die Software, aber ich war auch Tester und Mentor, d.h. ich habe auf Fehler und wünschenswerte Features hingewiesen. Nun, das dauerte zwar ein wenig, aber dann war die erste Version fertig, schneller, als ich das selbst hinbekommen hätte, und außerdem weitaus effizienter als mit Stack Overflow. Diese erste Version hatte dann nur noch einen Fehler, wenn eine Zeile länger war als die Begrenzung, erzeugte das Skript einen Teil, der die Begrenzung überschritt.

Also gab ich ChatGPT den Auftrag, eine Lösung dafür zu finden, und erklärte ihm, dass er Zeilen, die länger als die Begrenzung sind, eben doch umbrechen soll, mit einem (optischen) Hinweis auf die Fortsetzung im nächsten Teil, und dass zusätzlich nicht mitten in einem Wort getrennt werden soll. Interessanterweise landete ChatGPT dabei dann völlig im Wald und erwies sich als hoffnungslos überfordert, eine Lösung für dieses Problemchen zu programmieren. Am Ende war sogar der Code völlig zerstört (nichts funktionierte mehr), und ChatGPT gab irgendwann tatsächlich auf (es erzeugte keinen neuen Code mehr).

Nun ja. Das kleine Python-Tool finden Sie untenstehend. Vielleicht können Sie es einmal brauchen, es eignet sich übrigens auch für Twitter u.dgl. (Für Twitter etc. müsste man aber mit –max-chars eine andere Begrenzung setzen, der voreingestellte Default ist für ChatGPT-Prompts).

Den Teil, den ChatGPT nicht geschafft hat, habe ich dann eben selbst hinzugefügt (er ist mit blauer Schrift gekennzeichnet). Ich fand das insgesamt eine recht spannende Erfahrung. Eine Fragestellung, die ich durchaus als nicht so trivial empfand, wurde mit einigen Anläufen und Hilfestellung (z.B. ist das RegEx-Muster zur Erkennung der Teiler von mir – das muss unbedingt eindeutig sein, damit es nicht versehentlich falsch aufteilt, und das Muster, das ChatGPT zuerst vorschlug, hatte diese Gefahr) recht ordentlich gelöst. Aber bei etwas, das auf mich nicht allzu kompliziert gewirkt hat (und es dann auch nicht war), verrannte sich ChatGPT völlig. Auch dass ChatGPT den ursprünglich funktionierenden Entwurf bei diesem Fehlerbehebungsversuch völlig zerstörte, zeigt m.Mng., dass ChatGPT zwar eine große Hilfe beim Programmieren sein kann, aber ohne die Zusammenarbeit und die Hilfe eines menschlichen Entwicklers ist es, zumindest bisher, aussichtslos. Das wird dauern, bis ChatGPT Programmierer ersetzen kann – falls das jemals überhaupt eintreten wird. Die sich selbst weiter entwickelnde KI ist noch in weiter Ferne, würde ich meinen.

import argparse, os, re

def split_text(input_filename, output_filename, max_chars, delimiter, single_output, replace_input):
    with open(input_filename, 'r') as file:
        text = file.read()

    paragraphs = text.split(delimiter)
    result = []
    part_count = 1
    result.append(f"Teil {part_count:02}\n{'='*20}\n")
    char_count = len("Teil 01\n" + "=" * 20 + "\n")
    header_length = len(f"Teil {part_count:02}\n" + "=" * 20 + "\n")

    for paragraph in paragraphs:
        if char_count + len(paragraph) + len(delimiter) > max_chars:
            part_count += 1
            result.append(f"Teil {part_count:02}\n{'='*20}\n")
            char_count = header_length
            
        while len(paragraph) + header_length > max_chars:
            slice_pos = max_chars-header_length
            while slice_pos >= 0:
                if paragraph[slice_pos] == " ":
                    break
                slice_pos -= 1
            if slice_pos == 0:
                slice_pos = max_chars-header_length
            else:
                slice_pos += 1
                pglist = list(paragraph)
                pglist[slice_pos-1] = '>'
                paragraph = ''.join(pglist)
            result.append(paragraph[:slice_pos])
            result.append(delimiter)
            paragraph=paragraph[slice_pos:]
            part_count += 1
            result.append(f"Teil {part_count:02}\n{'='*20}\n")
            char_count = header_length

        result.append(paragraph)
        result.append(delimiter)
        char_count += len(paragraph) + len(delimiter)

    if single_output:
        if replace_input:
            os.remove(input_filename)
        with open(output_filename, 'w') as file:
            file.write("".join(result))
    else:
        base, ext = os.path.splitext(output_filename)
        for i, part in enumerate(re.split("Teil\s\d+(?=\n)\n====", "".join(result))[1:]):
            with open(f"{base}-{i+1:02}{ext}", 'w') as file:
                file.write(f"Teil {i+1:02}\n===={part}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Split text files into smaller parts.")
    parser.add_argument('input', help="Input filename")
    parser.add_argument('-o', '--output', help="Output filename", default=None)
    parser.add_argument('-m', '--max-chars', type=int, help="Maximum number of characters per part", default=2048)
    parser.add_argument('-d', '--delimiter', help="Delimiter between paragraphs", default="\n\n")
    parser.add_argument('-s', '--single-output', action='store_true', help="Store the result in a single output file")
    parser.add_argument('-r', '--replace-input', action='store_true', help="Replace the input file with the result")

    args = parser.parse_args()

    if args.output is None and not args.replace_input:
        parser.error("Output filename must be provided if not using --replace-input")

    output_filename = args.output if args.output is not None else args.input
    
    split_text(args.input, output_filename, args.max_chars, args.delimiter, args.single_output, args.replace_input)

Sie können das Script entweder aus obiger Box herauskopieren, oder eine Archivdatei herunterladen. (OpenAI erhebt keinerlei Anspruch auf Copyright etc. und stimmt deshalb der Veröffentlichung zu).

Noch zwei Hinweise: Sollte bei Ihnen eine Teildatei auf Platte größer werden als die Begrenzung, liegt das vermutlich an Umlauten, bzw. daran, dass UTF8 für gewisse Zeichen auf Platte zwei Bytes erzeugt. Der tatsächliche Text in einer Teildatei wird aber (incl. Überschrift und Trenner) niemals größer als die Begrenzung. Außerdem müsste man eigentlich noch den Fall abgefangen, dass max_chars kleiner angegeben wäre als die Länge der Separatoren, aber dazu war ich zu faul, wer würde schon so kleine Teile brauchen?

SELinux zieht die Zügel an

https://www.phoronix.com/news/SELinux-No-More-Runtime-Disable

After being deprecated for several years, Security Enhanced Linux „SELinux“ beginning with the Linux 6.4 kernel can no longer be run-time disabled.

Falls Sie künftig SELinux abschalten möchten, müssen Sie das mit dem Kernel-Parameter „selinux=0“ tun, die Laufzeitunterstützung dafür wird entfernt. Oder Sie verwenden den Eintrag „SELINUX=permissive“ in /etc/selinux/config – das hat den Vorteil, dass für mögliche Sicherheitsverstöße zumindest ein Log-Eintrag erstellt wird, obwohl SELinux auch damit defacto abgeschaltet ist.

Neue Unreal-Engine (v5)

https://www.golem.de/news/drama-unrecord-bietet-echt-aussehende-bodycam-action-2304-173589.html

Das französische Spielestudio Drama sorgt mit einem Trailer für Gesprächsstoff in der Community. Es geht um ein Actionspiel namens Unrecord, dessen Bewegtbilder sehr an echte Aufnahmen von Bodycams erinnern, wie sie Polizisten oder Soldaten im Einsatz tragen. Tatsächlich soll das Material aber auf Basis der Unreal Engine 5 vollständig in auf einem PC berechnet worden sein.

Was mittlerweile im Bereich Computergrafik möglich ist, ist wahlweise faszinierend oder erschreckend. Sicher, im Beispielvideo (siehe Beitrag auf golem.de) für Unrecord gibt es genügend Dinge, anhand derer man den künstlichen Ursprung immer noch erkennen kann. Aber dass die Entwicklung rasant voranschreitet, wird man nicht bestreiten können, und das Missbrauchspotential dürfte enorm sein.