diff --git a/apps/tesm/pyproject.toml b/apps/tesm/pyproject.toml
index 88b8615..300bd98 100644
--- a/apps/tesm/pyproject.toml
+++ b/apps/tesm/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "tesm"
-version = "2.8.22"
+version = "2.8.23"
description = "TESM -- Verwaltung und Ueberwachung von PoE-Endgeraeten und Aruba-Switchen"
requires-python = ">=3.11"
dependencies = [
diff --git a/apps/tesm/src/tesm/templates/tesm/screen.html b/apps/tesm/src/tesm/templates/tesm/screen.html
index 85d83a7..55da0bd 100644
--- a/apps/tesm/src/tesm/templates/tesm/screen.html
+++ b/apps/tesm/src/tesm/templates/tesm/screen.html
@@ -51,7 +51,9 @@
action="{{ url_for('screen.probe', device_id=device.id) }}">
diff --git a/packages/tesm-core/pyproject.toml b/packages/tesm-core/pyproject.toml
index ba907d0..d78849c 100644
--- a/packages/tesm-core/pyproject.toml
+++ b/packages/tesm-core/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "tesm-core"
-version = "2.8.12"
+version = "2.8.13"
description = "Gemeinsames Anwendungsgeruest (Auth, RBAC, Navigation, Design-System, Migrationen) fuer TESM und TESM-Lizenzserver"
requires-python = ">=3.11"
dependencies = [
diff --git a/packages/tesm-core/src/tesm_core/static/tesm_core/js/screen.js b/packages/tesm-core/src/tesm_core/static/tesm_core/js/screen.js
index 01953c8..235bcff 100644
--- a/packages/tesm-core/src/tesm_core/static/tesm_core/js/screen.js
+++ b/packages/tesm-core/src/tesm_core/static/tesm_core/js/screen.js
@@ -66,6 +66,24 @@ const HOECHSTENS = 2;
//: jedes Ereignis, und die Seite stuende stumm bis zum Seitenwechsel.
const AUFBAU_GRENZE = 12000;
+//: Verfahren, die im Browser keinen Schluesseltausch kosten.
+//:
+//: Der Grund steht in der Bibliothek, `core/ra2.js`: fuer RA2ne erzeugt der
+//: **Browser** bei jeder Sitzung ein eigenes 2048-Bit-RSA-Schluesselpaar, in
+//: JavaScript. Die Primzahlsuche dafuer dauert ein bis drei Minuten -- genau
+//: die Zeit, die zwischen Klick und Bild lag. "Ohne Authentifizierung" (1)
+//: kostet davon nichts.
+//:
+//: Deshalb kommt es zuerst, **wenn der Server es anbietet** und wir nicht
+//: ohnehin schon wissen, was hier traegt. Das ist nicht dieselbe Vorauswahl
+//: wie in 2.8.14: die war geraten, diese steht auf einer Messung. Traegt sie
+//: nicht, nimmt der zweite Anlauf die Reihenfolge des Servers -- dann dauert
+//: es eben.
+const OHNE_SCHLUESSELTAUSCH = new Set([1]);
+
+//: RA2ne. Wird es ausgehandelt, ist die Wartezeit erklaerbar und kein Fehler.
+const RA2NE = 6;
+
//: Tastenkombinationen, die der Arbeitsplatz selbst abfaengt und die deshalb
//: einen Knopf brauchen. X11-Keysyms.
const ALT_LINKS = 0xffe9;
@@ -196,6 +214,17 @@ export function starteSitzung(wurzel, quelle) {
versuche += 1;
window.clearTimeout(aufbauUhr);
aufbauUhr = window.setTimeout(() => {
+ // Ein ausgehandeltes RA2ne ist kein Fehler, sondern Rechenzeit: der
+ // Browser erzeugt dafuer gerade einen 2048-Bit-Schluessel. Das zu
+ // melden ist das Gegenteil einer Warnung -- es nimmt die Sorge.
+ if (rfb && rfb._rfbAuthScheme === RA2NE) {
+ melden(
+ "Der Server verlangt RA2ne (RSA-AES). Dafür erzeugt der Browser ein " +
+ "2048-Bit-Schlüsselpaar – das dauert ein bis drei Minuten. Bitte warten.",
+ "warnung",
+ );
+ return;
+ }
melden("Es kommt keine Antwort. Wird geprüft, woran es liegt …", "warnung");
streckeTesten().then((steht) => {
melden(
@@ -212,18 +241,28 @@ export function starteSitzung(wurzel, quelle) {
});
}, AUFBAU_GRENZE);
- // Zwei Regeln, beide aus Erfahrung und keine aus Vermutung:
+ // Drei Regeln, alle aus Messung und keine aus Vermutung:
//
- // 1. Was schon einmal getragen hat, kommt zuerst -- aber nur beim ersten
- // Anlauf. Ohne das faengt jede Sitzung wieder mit der ersten Wahl des
- // Servers an, die hier schon abgerissen ist, und ein sperrender
- // RealVNC Server laesst sich mit der Absage Minuten Zeit.
- // 2. Was abgerissen ist, wird nicht noch einmal gewaehlt.
+ // 1. Was schon einmal getragen hat, kommt zuerst.
+ // 2. Sonst das Verfahren ohne Schluesseltausch -- aber nur, wenn der
+ // Server es nachweislich anbietet (sonst faende noVNC gar keines und
+ // scheiterte sofort). RA2ne kostet sonst ein bis drei Minuten
+ // Rechenzeit im Browser, jedes Mal.
+ // 3. Was abgerissen ist, wird nicht noch einmal gewaehlt.
+ //
+ // Beides gilt nur fuer den **ersten** Anlauf; danach zaehlt die
+ // Reihenfolge des Servers, abzueglich dessen, was schon abgerissen ist.
const bewaehrt = daten.bewaehrt || 0;
- const zuerst = versuche === 1 && bewaehrt > 0 && !gescheitert.has(bewaehrt);
+ const angeboten = daten.verfahren || [];
+ const schnell = angeboten.filter((typ) => OHNE_SCHLUESSELTAUSCH.has(typ));
+ let bevorzugt = 0;
+ if (versuche === 1) {
+ if (bewaehrt > 0 && !gescheitert.has(bewaehrt)) bevorzugt = bewaehrt;
+ else if (schnell.length && !gescheitert.has(schnell[0])) bevorzugt = schnell[0];
+ }
RFB.prototype._isSupportedSecurityType = function (typ) {
if (gescheitert.has(typ)) return false;
- if (zuerst) return typ === bewaehrt;
+ if (bevorzugt) return typ === bevorzugt;
return istUnterstuetzt.call(this, typ);
};