feat(fls): export the editor model's programs

exportProject.ts, step X4a: each installed program of a PC or notebook as
the FILIUS application of its class, keyed by that class name as Java keys
them, with its settings: servers switched on as the model has them, a web
server's port and virtual hosts, the DNS server's recursion on port 53, the
echo server's port, the generic client's target (none as null, as its
constructor leaves it), the peer count, the personal firewall. E-mail
contents are the next step.

The model lost a web server's virtual hosts switch (useVHost, on for 3 web
servers in the corpus); Swift sets it off on import. The core now has
WebServerConfiguration.virtualHosts (Swift's name), the import carries
Java's value, and the Swift comparison names Swift's error.

Checked by Java: every corpus file, imported, exported and written, loads
with the programs of the original, with no new departure. In the synthetic
model the PC has every program with settings away from the defaults, the
notebook programs without settings (Java's defaults, 3 peers), where Java
makes /peer2peer itself. 12 mutation probes, each loaded by Java, were all
caught.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 09:17:30 +00:00
co-authored by Claude Opus 5.5
parent 698a775c37
commit 95daa64276
7 changed files with 1927 additions and 131 deletions
+2 -2
View File
@@ -37,7 +37,7 @@ Swift-Pfade relativ zu `filius-ipad/ios/FiliusPad/TopologyEditor/` (Stand
| `src/zip.ts` | `Persistence/TopologyFLSArchive.swift` (Fehler, Grenzen, Pfadregeln, ZIP-Leser/-Schreiber, CRC-32) | übertragen; DEFLATE über `fflate`, mit Apples Abschneide-Verhalten nachgebildet; Pfadfaltung (NFC, Breite, volles Case-Folding) an 41 Paaren gegen das Swift-Orakel gemessen |
| `src/archive.ts` | ebenda, Archiv-Teil von Import und Export | übertragen, ohne die XML-Ebene |
| `src/javabeans.ts`, `src/javaDefaults.json` | — | neu: XMLEncoder-Leser nach den Regeln von `java.beans.XMLDecoder` (Swift liest elementweise und verliert geteilte Werte); Getter-Standardwerte und statische Konstanten mit `tools/java-oracle` gemessen |
| `src/importProject.ts` | `Persistence/TopologyProjectStore.swift` (Knoten, Ports, Kabel, IP-Konfiguration, Switch/WLAN, Routen, RIP, Firewall, DHCP, Portweiterleitung, Modem, Dateisysteme, Programme, Doku-Elemente des Imports) | übertragen, Eingabe ist Javas Sicht: Name und Port-Anzahl wie Java, abgelehnte Adresse → Swift-Standard, Router-Standardgateway wie Java (Swift verliert es), jede Router-Firewall eingetragen, Konfigurationstexte wie in Swift getrimmt (`swiftTrim`), Rechner ohne Dateisystem leer wie in Java (Swift: Demo-Dateien), alle Programme bleiben (Swift verwirft sechs), Webserver-Dateien bleiben in `/webserver` (Swift: `/www`), keine versteckten Zustandsdateien im Dateisystem, DNS-Einträge so, wie Javas Server sie aus `/dns/hosts` beantwortet, WLAN eines Rechners eingeschaltet nach Javas Funk-Merkmal der Karte (auch ohne SSID; Swift: jede SSID); gegen Swifts importiertes Modell auf 13 Dateien geprüft |
| `src/importProject.ts` | `Persistence/TopologyProjectStore.swift` (Knoten, Ports, Kabel, IP-Konfiguration, Switch/WLAN, Routen, RIP, Firewall, DHCP, Portweiterleitung, Modem, Dateisysteme, Programme, Doku-Elemente des Imports) | übertragen, Eingabe ist Javas Sicht: Name und Port-Anzahl wie Java, abgelehnte Adresse → Swift-Standard, Router-Standardgateway wie Java (Swift verliert es), jede Router-Firewall eingetragen, Konfigurationstexte wie in Swift getrimmt (`swiftTrim`), Rechner ohne Dateisystem leer wie in Java (Swift: Demo-Dateien), alle Programme bleiben (Swift verwirft sechs), Webserver-Dateien bleiben in `/webserver` (Swift: `/www`), keine versteckten Zustandsdateien im Dateisystem, DNS-Einträge so, wie Javas Server sie aus `/dns/hosts` beantwortet, WLAN eines Rechners eingeschaltet nach Javas Funk-Merkmal der Karte (auch ohne SSID; Swift: jede SSID); der Webserver behält Javas Schalter für virtuelle Hosts (Swift: aus); gegen Swifts importiertes Modell auf 13 Dateien geprüft |
| `test/importProject.test.ts` | — | neu: Swifts importiertes Modell (13 Dateien, begründete Abweichungen; im Dateisystem ausgenommen nur Swifts versteckte Zustandsdateien), Vollständigkeit aller 23, Pings im Kern (über einen Router; über drei Router mit manuellen Routen und Router-Gateways) |
| `src/systemSoftware.ts` | Java `SwitchFirmware`, `Betriebssystem`, `VermittlungsrechnerBetriebssystem`, `GatewayFirmware`, `Weiterleitungstabelle`, `Firewall`, `FirewallRule`, `DHCPServer`, `ModemFirmware`, `Dateisystem`, `Datei` | neu nach Java: SSID, Lernzeit, RIP, manuelle Routen, Router-Firewall (an allen Stellen, an denen die Datei sie erreicht), DHCP (ein kaputter statischer Eintrag fällt allein weg, Java verliert alle folgenden), statische NAT, Modem, Dateisystem (bei Router und Heimrouter das, was die Datei zu den Vorlagen des Konstruktors hinzufügt, oder eine eigene Wurzel, die sie ersetzt), installierte Programme von Rechner und Notebook; `Character.isWhitespace` am JDK gemessen; gegen Java geprüft |
| `src/javaIp.ts` | Java `IP.inetAton`/`ipCheck` | neu nach Java; an 46 Fällen mit Java gemessen |
@@ -51,7 +51,7 @@ Swift-Pfade relativ zu `filius-ipad/ios/FiliusPad/TopologyEditor/` (Stand
| `test/javaBeansWriter.test.ts`, `test/beans/` | — | neu: 11 Dateien des Schreibers, von Javas `XMLDecoder` gelesen und beschrieben; Erwartungen von Hand |
| `src/topologyWriter.ts` | Java `SzenarioVerwaltung.netzwerkSpeichern`, Konstruktoren von `NetzwerkInterface`, `Port`, `GUIKabelItem` und der Systemsoftware | neu nach Java: `konfiguration.xml` aus Javas Sicht — Geräte, Schnittstellen (vom Konstruktor angelegte über Getter, weitere per `add`), Ports über Getter-Verweise, Kabel samt Zeichen-Enden (`kabelpanel`), Doku-Elemente; Systemsoftware über ihre Setter: SSID, Lernzeit, RIP, manuelle Routen, DHCP-Client und -Server, statische NAT, Modem, Router-Firewall (über das `konfig`-Plug-in des Webservers, wie XMLEncoder sie erreicht); Dateisysteme (an die Wurzel des Konstruktors angehängt wie bei XMLEncoder, beim Router hinter dessen Vorlagen); installierte Programme nach den Dateien (Webserver, Tauschbörse und E-Mail-Server legen ihre Ordner nur an, wo sie fehlen; der DNS-Server liest `/dns/hosts` beim Installieren), je unter ihrem Schlüssel mit der Systemsoftware wie `installApp`, samt Einstellungen und persönlicher Firewall; E-Mail: Domain und Bean-Konten des Servers samt Postfächern, Ordner und Adressbuch des Clients (sein Konto steht in `/konten.txt`, einer Datei); Javas Fehler nicht übernommen: ein Empfänger, den eine ältere Datei als Zeichenkette hält, wird als der `AddressEntry` geschrieben, den Javas `AddressEntry(String)` daraus macht (Java legt die Zeichenkette ungeprüft in die typisierte Liste, sein E-Mail-Fenster scheitert daran), ein `null`-Empfänger fällt weg; Kopf „Filius version: 2.14.0 (mdg-filius)“ |
| `test/topologyWriter.test.ts`, `test/written.java.json` | — | neu: alle 23 Korpus-Dateien gelesen und neu geschrieben, von Java geladen — Topologie, Systemsoftware, Dateisysteme und Programme samt E-Mail wie beim Original (bis auf die benannte Abweichung bei Empfängern als Zeichenkette, nur in `man-in-the-middle.fls`) (Java gegen Java); dazu eine künstliche Topologie mit dem, was der Korpus nicht hat (u. a. eingeschaltete Router-Firewall mit Regeln jedes Protokolls, alle Firewall-Schalter abseits der Vorgabe, Modem mit eigenem Port und Ziel, verschachtelter Dateibaum mit umbenannter Wurzel, namenlosem Ordner, Datei ohne Typ und Inhalt mit CR/CRLF und Zeichen jenseits der BMP, Heimrouter mit eigener Wurzel, jedes Filius-Programm mit Einstellungen abseits der Vorgabe samt persönlicher Firewall, von Java angelegte Ordner `/peer2peer` und `/mailserver`, E-Mail-Server und -Client mit Konto, Postfach, drei Ordnern, Adressbuch und Empfängern aller Formen) |
| `src/exportProject.ts` | Gegenstück zu `importProject.ts`; Java `JHostKonfiguration.updateWifiConnection`, `InternetKnotenBetriebssystem.getStandardGateway`/`setStandardGateway` | neu: Editor-Modell → Javas Sicht für den Schreiber, Schritt X1 Topologie — Geräte, Schnittstellen (MAC wie in der Simulation: aus der Datei oder aus der Port-ID abgeleitet), Kabel samt Funk (Karte drahtlos und Switch, wie Java verbindet), Gateway und DNS an allen Schnittstellen wie Javas eigene Setter, Doku-Elemente; X2 Systemsoftware — SSIDs, Lernzeit, Routen, RIP, DHCP-Client und -Server, Portweiterleitung, Firewall (Namen des Kerns als Javas Zahlen), Modems aus den Paaren des Modells (Port aus dem Paarnamen, der erste eines Paars dient, Ziel `localhost`); X3 Dateien von Rechner und Notebook — Typ aus der Inhaltsart (Text nach Endung, sonst `text`; Bild und Binärdaten nach Medientyp), Bilder und Binärdaten in Base64 wie Filius' `Base64.encodeBytes` (Umbruch nach 76 Zeichen, an 19 Längen mit Java gemessen) |
| `src/exportProject.ts` | Gegenstück zu `importProject.ts`; Java `JHostKonfiguration.updateWifiConnection`, `InternetKnotenBetriebssystem.getStandardGateway`/`setStandardGateway` | neu: Editor-Modell → Javas Sicht für den Schreiber, Schritt X1 Topologie — Geräte, Schnittstellen (MAC wie in der Simulation: aus der Datei oder aus der Port-ID abgeleitet), Kabel samt Funk (Karte drahtlos und Switch, wie Java verbindet), Gateway und DNS an allen Schnittstellen wie Javas eigene Setter, Doku-Elemente; X2 Systemsoftware — SSIDs, Lernzeit, Routen, RIP, DHCP-Client und -Server, Portweiterleitung, Firewall (Namen des Kerns als Javas Zahlen), Modems aus den Paaren des Modells (Port aus dem Paarnamen, der erste eines Paars dient, Ziel `localhost`); X3 Dateien von Rechner und Notebook — Typ aus der Inhaltsart (Text nach Endung, sonst `text`; Bild und Binärdaten nach Medientyp), Bilder und Binärdaten in Base64 wie Filius' `Base64.encodeBytes` (Umbruch nach 76 Zeichen, an 19 Längen mit Java gemessen); X4a Programme — je Programm die Filius-Klasse unter ihrem Namen als Schlüssel, eingeschaltete Server, Ports, virtuelle Hosts, DNS-Rekursion, Ziel des Clients (leer als `null` wie Javas Konstruktor), Teilnehmerzahl, persönliche Firewall |
| `test/exportProject.test.ts`, `test/exported.java.json` | — | neu: alle 23 Korpus-Dateien importiert, exportiert, geschrieben und von Java geladen — Topologie wie beim Original bis auf benannte Abweichungen (abgeleiteter MAC und abgeleitete Switch-SSID statt gewürfelter, Modem-Rollen nach Reihenfolge im Paar, Doku in Zeichenreihenfolge mit Text, Schrift und Mindestgröße des Modells, Dateien in der Ordnung und mit dem Typ des Modells, keine eigenen Dateien von Routern); dazu ein künstliches Modell, das Java ebenfalls lädt |
| `src/importEmail.ts` | `Persistence/TopologyProjectStore.swift` (`registerJavaEmailConfigurations`, `assignedJavaEmailMessages`) | übertragen, Eingabe ist Javas Sicht: Server-Konten aus `/mailserver/konten.txt`, ohne Datei aus der Bean-Liste (Java verlöre sie); Client-Konto aus `/konten.txt`, ohne Datei aus der älteren `kontoListe` (Filius 2.14 liest sie nicht mehr); Konten und Nachrichten bleiben, wo Swift verwirft, was seine Prüfung nicht besteht; Vor- und Nachname getrennt; Empfangszeit nur aus der Datei (Swift nummeriert); gegen Swifts Modell geprüft |
| `test/importEmail.test.ts`, `test/email-*.swift.json` | `State/TopologyEmail.swift` (`decodeJavaServer`, `decodeJavaClient`) als Vergleich | neu: dieselben 43 Kontodateien mit Swifts Leser; wie Swift bis auf benannte Fälle, in denen Swift prüft und die ganze Datei verwirft, wo Java liest |
+2
View File
@@ -172,6 +172,8 @@ export interface WebServerConfiguration {
readonly port: number;
/** Where the served files are: Java keeps them in /webserver, Swift moves them to /www. */
readonly documentRoot: string;
/** Serve by host name, from the hosts named in www.conf/vhosts (Java's useVHost). */
readonly virtualHosts: boolean;
}
export const DEFAULT_WEB_SERVER_PORT = 80;
+77 -4
View File
@@ -21,7 +21,17 @@
// Java's root, each file a Datei of the type Java's importer reads it by —
// text by its extension (else "text"), an image or binary data by its media
// type, in Base64 as FILIUS's Base64.encodeBytes writes it (javaBase64). A router or home
// router keeps the files its constructor makes; the model holds none for it. System software, files and programs
// router keeps the files its constructor makes; the model holds none for it.
//
// The programs of a PC or notebook: each installed program as the FILIUS
// application of its class, under that class name as Java keys them, with
// its settings — a server switched on as the model has it, a web server's
// port and virtual hosts, the DNS server's recursion (on port 53, where the
// model keeps it), the echo server's port, the generic client's target, the
// peer count, the personal firewall. A DNS server's records are in
// /dns/hosts, one of the files, and it forwards to the host's DNS server as
// Java's does. E-mail accounts, messages and address books are a later
// step. System software, files and programs
// follow in later steps.
//
// What the model keeps is written as it keeps it, and so differs from the
@@ -40,7 +50,9 @@
// derives from the node's id;
// - files in the model's order (directories first, then by name) and of the
// type their kind says, not the one the file named; a router's own files
// (a web server's www.conf) are not in the model.
// (a web server's www.conf) are not in the model;
// - a peer-to-peer application's peer count the file lacked (Java rolls
// 3, 4 or 5) is the model's 3.
//
// Checked by Java: every corpus file, imported, exported and written, loads in
// Java FILIUS to the topology of the original up to those departures.
@@ -52,10 +64,17 @@ import {
effectiveMacAddress,
firewallConfiguration,
FIREWALL_PROTOCOL,
JAVA_PERSONAL_FIREWALL_DEFAULTS,
interfaceKey,
type DeviceConfiguration,
type DhcpClientConfiguration,
type DhcpServerConfiguration,
type DnsServerConfiguration,
type EchoServerConfiguration,
type GnutellaConfiguration,
type InstallableProgram,
type SimpleClientConfiguration,
type WebServerConfiguration,
type FirewallConfiguration,
type GatewayPortForwardingRow,
type ManualRoute,
@@ -72,9 +91,10 @@ import {
type TopologyNode,
type VirtualFileSystem,
} from '@mdg-filius/core';
import type { FlsDhcpServer, FlsFileTree, FlsFirewall } from './systemSoftware.js';
import { PROGRAM_OF_CLASS } from './importProject.js';
import type { FlsApplicationClass, FlsDhcpServer, FlsFileTree, FlsFirewall } from './systemSoftware.js';
import type { FlsDocumentationItem, FlsInterface, FlsLink, FlsNodeClass } from './topology.js';
import type { NodeToWrite, SystemToWrite, TopologyToWrite } from './topologyWriter.js';
import type { ApplicationToWrite, NodeToWrite, SystemToWrite, TopologyToWrite } from './topologyWriter.js';
/** The parts of the editor model the topology is made of. */
export interface ProjectToExport {
@@ -91,6 +111,13 @@ export interface ProjectToExport {
readonly portForwardingRowsByNodeId: ReadonlyMap<Id, readonly GatewayPortForwardingRow[]>;
readonly remoteLinkConfigurations: ReadonlyMap<Id, RemoteLinkConfiguration>;
readonly virtualFileSystems: ReadonlyMap<Id, VirtualFileSystem>;
readonly installedPrograms: ReadonlyMap<Id, ReadonlySet<InstallableProgram>>;
readonly activePrograms: ReadonlyMap<Id, ReadonlySet<InstallableProgram>>;
readonly webServerConfigurations: ReadonlyMap<Id, WebServerConfiguration>;
readonly gnutellaConfigurations: ReadonlyMap<Id, GnutellaConfiguration>;
readonly dnsServerConfigurations: ReadonlyMap<Id, DnsServerConfiguration>;
readonly echoServerConfigurations: ReadonlyMap<Id, EchoServerConfiguration>;
readonly simpleClientConfigurations: ReadonlyMap<Id, SimpleClientConfiguration>;
readonly documentationItems: readonly DocumentationItem[];
}
@@ -223,6 +250,7 @@ function exportSystem(node: TopologyNode, project: ProjectToExport, servingModem
...system,
ssid: ssid === '' ? null : ssid,
fileSystem: { kind: 'directory', name: 'root', children: files === undefined ? [] : fileTrees(files, '/') },
applications: exportPrograms(id, project),
};
}
case 'router':
@@ -245,6 +273,51 @@ function exportSystem(node: TopologyNode, project: ProjectToExport, servingModem
}
}
const CLASS_OF_PROGRAM = Object.fromEntries(
Object.entries(PROGRAM_OF_CLASS).map(([javaClass, program]) => [program, javaClass]),
) as Readonly<Record<InstallableProgram, FlsApplicationClass>>;
const DNS_PORT = 53;
const ECHO_PORT = 55_555;
function exportPrograms(id: Id, project: ProjectToExport): ApplicationToWrite[] {
const active = project.activePrograms.get(id);
return [...(project.installedPrograms.get(id) ?? [])].map((program): ApplicationToWrite => {
const javaClass = CLASS_OF_PROGRAM[program];
const application = { key: javaClass, javaClass };
const isActive = active?.has(program) === true;
switch (program) {
case 'webServer': {
const web = project.webServerConfigurations.get(id);
return { ...application, isActive, port: web?.port ?? 80, useVirtualHosts: web?.virtualHosts === true };
}
case 'dnsServer':
return {
...application,
isActive,
port: DNS_PORT,
recursiveResolutionEnabled: project.dnsServerConfigurations.get(id)?.recursiveResolutionEnabled === true,
};
case 'echoServer':
return { ...application, isActive, port: project.echoServerConfigurations.get(id)?.port ?? ECHO_PORT };
case 'simpleClient': {
const client = project.simpleClientConfigurations.get(id);
// No target is null, as ClientBaustein's constructor leaves it.
const target = client?.targetAddress ?? '';
return { ...application, targetAddress: target === '' ? null : target, targetPort: client?.targetPort ?? ECHO_PORT };
}
case 'gnutella':
return { ...application, maxPeers: project.gnutellaConfigurations.get(id)?.maximumKnownPeers ?? 3 };
case 'firewall':
return { ...application, firewall: exportFirewall(project.firewallConfigurationsByNodeId.get(id) ?? JAVA_PERSONAL_FIREWALL_DEFAULTS) };
case 'emailServer':
return { ...application, isActive };
default:
return application;
}
});
}
/** The text types Java's importer reads as text, named by a file's extension. */
const TEXT_EXTENSIONS = new Set(['txt', 'html', 'htm', 'css', 'xml', 'csv', 'conf', 'log']);
+3 -1
View File
@@ -34,7 +34,8 @@
// prompt, text editor, file explorer, image viewer, echo server and
// generic client, and their settings (port, target) have a place here;
// - a web server's files stay in /webserver (its document root), where Swift
// moves them to /www; and no program state is written into a host's files
// moves them to /www, and it keeps Java's virtual hosts switch (Swift sets
// it off); and no program state is written into a host's files
// (Swift keeps Gnutella and e-mail state there as hidden JSON files).
// - e-mail: see importEmail.ts;
// - a DNS server's records are what Java's server answers from /dns/hosts
@@ -422,6 +423,7 @@ function registerPrograms(source: FlsNode, node: TopologyNode, system: SystemCon
system.webServerConfigurations.set(node.id, {
port: application.port ?? DEFAULT_WEB_SERVER_PORT,
documentRoot: JAVA_WEB_ROOT,
virtualHosts: application.useVirtualHosts === true,
});
break;
case 'gnutella':
+110 -3
View File
@@ -19,6 +19,7 @@ import {
firewallRule,
stableGeneratedMacAddress,
type Id,
type InstallableProgram,
type TopologyNode,
VirtualFileSystem,
} from '@mdg-filius/core';
@@ -68,9 +69,21 @@ const original = JSON.parse(readFileSync(join(corpusRoot, 'corpus.java.json'), '
const exportedPath = join(here, 'exported.java.json');
const exported = JSON.parse(readFileSync(exportedPath, 'utf8')) as Record<string, JavaFile>;
/** The system software without its applications, a later step; files in any order. */
/**
* The system software without what a later step exports — the e-mail
* programs' domain, bean accounts, folders and address book; files in any
* order.
*/
function systemOf(system: Record<string, unknown>) {
const { applications: _applications, ...settings } = system;
const settings =
system.applications === undefined
? system
: {
...system,
applications: (system.applications as Record<string, unknown>[]).map(
({ mailDomain: _domain, beanAccounts: _accounts, received: _received, sent: _sent, drafts: _drafts, addressBook: _book, ...rest }) => rest,
),
};
return settings.fileSystem === undefined || settings.fileSystem === null
? settings
: { ...settings, fileSystem: sortedTree(settings.fileSystem as JavaTree) };
@@ -315,6 +328,13 @@ function emptyProject(): ProjectToExport {
portForwardingRowsByNodeId: new Map(),
remoteLinkConfigurations: new Map(),
virtualFileSystems: new Map(),
installedPrograms: new Map(),
activePrograms: new Map(),
webServerConfigurations: new Map(),
gnutellaConfigurations: new Map(),
dnsServerConfigurations: new Map(),
echoServerConfigurations: new Map(),
simpleClientConfigurations: new Map(),
documentationItems: [],
};
}
@@ -341,6 +361,10 @@ function syntheticFiles(): VirtualFileSystem {
files.writeImageFile('/foto.jpg', bytesOf(100), 'image/jpeg');
files.writeBinaryFile('/daten.bin', bytesOf(58), 'application/zip');
files.writeBinaryFile('/roh', bytesOf(3));
// The web server's and the peer-to-peer application's own: Java makes none.
files.createDirectory('/webserver');
files.writeTextFile('/webserver/index.html', '<p>own</p>');
files.createDirectory('/peer2peer');
return files;
}
@@ -400,6 +424,14 @@ const SYNTHETIC: ProjectToExport = {
]),
ripEnabledByNodeId: new Map([['rt', true]]),
firewallConfigurationsByNodeId: new Map([
[
'pc',
firewallConfiguration({
isActive: false,
defaultPolicy: 'accept',
rules: [firewallRule({ sourceIPAddress: '10.0.0.0', sourceSubnetMask: '255.0.0.0', port: 22, action: 'accept' })],
}),
],
[
'rt',
firewallConfiguration({
@@ -437,6 +469,34 @@ const SYNTHETIC: ProjectToExport = {
]),
portForwardingRowsByNodeId: new Map([['gw', [{ protocolValue: 'TCP', publicPortValue: '8080', lanIPAddress: '192.168.1.10', lanPortValue: '80' }]]]),
virtualFileSystems: new Map([['pc', syntheticFiles()]]),
installedPrograms: new Map<Id, Set<InstallableProgram>>([
[
'pc',
new Set<InstallableProgram>([
'webServer',
'dnsServer',
'echoServer',
'simpleClient',
'gnutella',
'firewall',
'commandPrompt',
'textEditor',
'fileExplorer',
'imageViewer',
'webBrowser',
]),
],
['nb', new Set<InstallableProgram>(['gnutella', 'simpleClient', 'firewall'])],
]),
activePrograms: new Map([['pc', new Set<InstallableProgram>(['webServer', 'dnsServer', 'echoServer'])]]),
webServerConfigurations: new Map([['pc', { port: 8080, documentRoot: '/webserver', virtualHosts: true }]]),
dnsServerConfigurations: new Map([['pc', { recursiveResolutionEnabled: true, records: [] }]]),
echoServerConfigurations: new Map([['pc', { port: 7777 }]]),
simpleClientConfigurations: new Map([
['pc', { targetAddress: '10.0.0.9', targetPort: 7777 }],
['nb', { targetAddress: '', targetPort: 55_555 }],
]),
gnutellaConfigurations: new Map([['pc', { maximumKnownPeers: 7 }]]),
remoteLinkConfigurations: new Map([
['m1', { pairIdentifier: 'java-modem-port-4242', latencyMilliseconds: 20, isEnabled: true }],
['m2', { pairIdentifier: 'java-modem-port-4242', latencyMilliseconds: 20, isEnabled: true }],
@@ -520,8 +580,33 @@ describe('a model beyond the corpus, as Java loads it', () => {
javaFile('foto.jpg', 'jpg', javaBase64(bytesOf(100))),
javaFile('index.HTML', 'html', '<p>upper case extension</p>'),
javaFile('roh', '', javaBase64(bytesOf(3))),
{ directory: 'webserver', children: [javaFile('index.html', 'html', '<p>own</p>')] },
{ directory: 'peer2peer', children: [] },
],
}),
// In the order of Java's key.
applications: [
{ key: 'filius.software.clientserver.ClientBaustein', class: 'filius.software.clientserver.ClientBaustein', zielIPAdresse: '10.0.0.9', zielPort: 7777 },
{ key: 'filius.software.clientserver.ServerBaustein', class: 'filius.software.clientserver.ServerBaustein', aktiv: true, port: 7777 },
{ key: 'filius.software.dateiaustausch.PeerToPeerAnwendung', class: 'filius.software.dateiaustausch.PeerToPeerAnwendung', maxTeilnehmerZahl: 7 },
{ key: 'filius.software.dns.DNSServer', class: 'filius.software.dns.DNSServer', aktiv: true, port: 53, recursiveResolutionEnabled: true },
{
key: 'filius.software.firewall.Firewall',
class: 'filius.software.firewall.Firewall',
activated: false,
defaultPolicy: 1,
dropICMP: false,
filterSYNSegmentsOnly: true,
filterUdp: true,
rules: [['10.0.0.0', '255.0.0.0', '', '', 22, 6, 1]],
},
{ key: 'filius.software.lokal.FileExplorer', class: 'filius.software.lokal.FileExplorer' },
{ key: 'filius.software.lokal.ImageViewer', class: 'filius.software.lokal.ImageViewer' },
{ key: 'filius.software.lokal.Terminal', class: 'filius.software.lokal.Terminal' },
{ key: 'filius.software.lokal.TextEditor', class: 'filius.software.lokal.TextEditor' },
{ key: 'filius.software.www.WebBrowser', class: 'filius.software.www.WebBrowser' },
{ key: 'filius.software.www.WebServer', class: 'filius.software.www.WebServer', aktiv: true, port: 8080, useVHost: true },
],
},
},
{
@@ -540,7 +625,29 @@ describe('a model beyond the corpus, as Java loads it', () => {
useIpAsName: false,
useMacAsName: true,
ports: [card('10.0.0.2', '255.255.255.0', stableGeneratedMacAddress('n0'), '', '', true)],
system: { ssid: 'net', manualRoutes: [], dhcpClient: false, dhcpServer: JAVA_DHCP_DEFAULTS, fileSystem: { directory: 'root', children: [] } },
system: {
ssid: 'net',
manualRoutes: [],
dhcpClient: false,
dhcpServer: JAVA_DHCP_DEFAULTS,
// Made by the peer-to-peer application.
fileSystem: { directory: 'root', children: [{ directory: 'peer2peer', children: [] }] },
applications: [
// Without a setting: no target (null), the model's 3 peers, Java's personal firewall.
{ key: 'filius.software.clientserver.ClientBaustein', class: 'filius.software.clientserver.ClientBaustein', zielIPAdresse: null, zielPort: 55_555 },
{ key: 'filius.software.dateiaustausch.PeerToPeerAnwendung', class: 'filius.software.dateiaustausch.PeerToPeerAnwendung', maxTeilnehmerZahl: 3 },
{
key: 'filius.software.firewall.Firewall',
class: 'filius.software.firewall.Firewall',
activated: true,
defaultPolicy: 0,
dropICMP: false,
filterSYNSegmentsOnly: true,
filterUdp: true,
rules: [],
},
],
},
},
{
class: 'Vermittlungsrechner',
File diff suppressed because it is too large Load Diff
+10 -2
View File
@@ -140,7 +140,7 @@ function systemOf(project: ImportedProject, nodeId: Id) {
const web = project.webServerConfigurations.get(nodeId);
if (web !== undefined) {
// Swift serves the same files from /www after moving them there.
result.webServer = { port: web.port, documentRoot: web.documentRoot === '/webserver' ? '/www' : web.documentRoot, virtualHosts: false };
result.webServer = { port: web.port, documentRoot: web.documentRoot === '/webserver' ? '/www' : web.documentRoot, virtualHosts: web.virtualHosts };
}
const gnutella = project.gnutellaConfigurations.get(nodeId);
if (gnutella !== undefined) result.gnutella = gnutella;
@@ -330,7 +330,15 @@ const unnumberedMailbox = (numbered: string[]) => (node: SwiftNode) => {
},
};
};
/** Swift reads a web server's useVHost as off. */
const servesVirtualHosts = (node: SwiftNode) => ({
...node,
system: { ...node.system, webServer: { ...(node.system.webServer as object), virtualHosts: true } },
});
const SWIFT_ERRORS: Record<string, Record<number, (node: SwiftNode) => SwiftNode>> = {
'ipad-fixtures/Public_and_Private_Networks_2_EN.fls': { 2: servesVirtualHosts },
'java-examples/Public_and_Private_Networks_2_EN.fls': { 2: servesVirtualHosts },
'java-examples/private_und_public_networks_mit_provider_DE.fls': { 6: servesVirtualHosts },
'java-examples/man-in-the-middle.fls': { 5: unnumberedMailbox(['1', '2']) },
'java-examples/multicast_server.fls': {
// useIPAsName is `<object idref="Boolean0"/>`, the shared result of a
@@ -894,7 +902,7 @@ describe('importProject rules', () => {
expect([...project.installedPrograms.get(notebook!)!].sort()).toEqual(['commandPrompt', 'echoServer', 'firewall', 'simpleClient', 'webServer']);
expect([...project.activePrograms.get(notebook!)!]).toEqual(['webServer']);
expect(project.webServerConfigurations.get(notebook!)).toEqual({ port: 8080, documentRoot: '/webserver' });
expect(project.webServerConfigurations.get(notebook!)).toEqual({ port: 8080, documentRoot: '/webserver', virtualHosts: false });
expect(project.echoServerConfigurations.get(notebook!)).toEqual({ port: 7 });
expect(project.simpleClientConfigurations.get(notebook!)).toEqual({ targetAddress: '10.0.0.9', targetPort: 7 });
expect(project.firewallConfigurationsByNodeId.get(notebook!)).toMatchObject({ isActive: true, defaultPolicy: 'accept' });